无系统调用时Linux信号的处理机制疑问
单CPU场景下用户态死循环进程能否处理信号?
我查阅过多本Linux书籍与教程,得知内核会在从内核态切换至用户态时处理信号。这一逻辑本合理,但测试如下代码后产生疑问:
> cat sig_timing.c #include <signal.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdbool.h> volatile bool done = false; static void sig_handler(int signo) { printf("Received signal %d (%s), current errno:%s\n", signo, strsignal(signo), strerror(errno)); done = true; } int main(int argc, char **argv) { signal(SIGALRM, sig_handler); alarm(3); while (!done) { strlen("Hello World!"); } return 0; } > gcc sig_timing.c > ./a.out Received signal 14 (Alarm clock), current errno:Success
主函数注册信号后进入无系统调用的死循环,按理应无机会进入内核及完成内核态到用户态的切换,也就无法触发信号处理函数,但实际却触发了。此前听到的解释针对多CPU场景:发送信号的内核线程会向目标进程所在CPU发送跨CPU消息引发硬件中断,使其进入内核再返回用户态。我想了解:在无超线程的单CPU场景下,用户态死循环中的进程能否得到信号处理?
在单CPU无超线程的场景下,用户态死循环的进程依然会被处理信号,核心原因是Linux的周期性时钟中断机制:
- Linux系统会周期性触发硬件时钟中断(默认通常为1ms一次),无论当前CPU正在执行用户态还是内核态代码,都会被该中断打断并强制进入内核态。
- 时钟中断触发后,内核会执行调度、计时等一系列核心逻辑,其中就包含检查当前进程是否有待处理的未决信号。如果发现存在待处理信号,内核会在从中断处理流程返回用户态之前,安排执行对应的信号处理函数。
- 回到测试代码:
alarm(3)会让内核在3秒后向进程发送SIGALRM信号。在这3秒内,进程持续执行用户态死循环,但期间会被无数次时钟中断打断进入内核。当内核在某次时钟中断处理时检测到SIGALRM信号已到达,就会在返回用户态时触发信号处理函数,最终出现代码运行中信号被处理的结果。
简言之,单CPU场景下无需跨CPU消息,周期性的硬件时钟中断会强制进程进入内核,让内核获得处理信号的机会,因此死循环的用户态进程依然能响应信号。
内容的提问来源于stack exchange,提问作者my_question
相关产品推荐
相关产品推荐

