面试题答案
一键面试信号处理机制分析
- 信号到达时的处理:在Linux系统中,信号是异步事件,当信号到达时,内核会为接收信号的进程设置一个信号掩码,并检查进程是否正在阻塞该信号。如果进程没有阻塞信号,内核就会调用相应的信号处理函数。
- 信号优先级:Linux内核并没有直接支持信号的绝对优先级概念。然而,可以通过设置信号处理函数的SA_SIGINFO标志,使用sigaction函数注册信号处理函数,然后通过实时信号(RT信号,范围为34 - 64)来模拟优先级。实时信号在排队和处理上与常规信号不同,实时信号可以排队,相同的实时信号会按照发送顺序依次处理,而常规信号不会排队,相同的常规信号多次发送只会被处理一次。
线程调度角度分析
- 线程与信号:在多线程程序中,信号通常会被发送到整个进程,而不是特定线程。但是,线程可以通过pthread_sigmask函数阻塞或解除阻塞信号,并且可以使用pthread_kill函数向特定线程发送信号。
- 调度干扰:当多个信号同时到达时,由于线程共享进程的信号处理上下文,如果没有正确处理,低优先级信号处理函数可能会干扰高优先级信号处理函数的执行。例如,低优先级信号处理函数可能会占用CPU时间,导致高优先级信号处理函数不能及时执行。
确保高优先级信号处理不被干扰的方法
- 信号掩码与阻塞:
- 在高优先级信号处理函数执行期间,使用pthread_sigmask函数阻塞低优先级信号。例如,在高优先级信号处理函数开始时,将低优先级信号添加到线程的信号掩码中,在处理函数结束时,再将其从信号掩码中移除。
sigset_t low_priority_mask; sigemptyset(&low_priority_mask); sigaddset(&low_priority_mask, LOW_PRIORITY_SIGNAL); pthread_sigmask(SIG_BLOCK, &low_priority_mask, NULL); // 高优先级信号处理代码 pthread_sigmask(SIG_UNBLOCK, &low_priority_mask, NULL);
- 实时信号的使用:
- 为高优先级信号选择较高编号的实时信号(如64号),为低优先级信号选择较低编号的实时信号(如34号)。实时信号会按照发送顺序依次处理,这样可以确保高优先级信号先被处理。
- 使用sigaction函数注册实时信号的处理函数,并设置SA_SIGINFO标志,以便能够获取信号的详细信息。
struct sigaction sa_high; sa_high.sa_sigaction = high_priority_handler; sa_high.sa_flags = SA_SIGINFO; sigemptyset(&sa_high.sa_mask); sigaction(HIGH_PRIORITY_RT_SIGNAL, &sa_high, NULL);
- 线程优先级调度:
- 可以使用POSIX线程调度函数(如pthread_setschedparam)为处理高优先级信号的线程设置更高的调度优先级。这样,在CPU资源竞争时,高优先级信号处理线程更有可能优先执行。
struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_FIFO); pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);