windows下信号机制的学习
以前没有注意过这个问题, 近期在代码中看到了用到windows下的signal, MSDN, 上网查了查, 并写了测试的代码, 得出以下结论:
1. windows下支持的信号时有限的, 在signal.h中定义, 分别是
SIGINT Ctrl+C中断
SIGILL 非法指令
SIGFPE 浮点异常
SIGSEGV 段错误, 非法指针访问
SIGTERM kill发出的软件终止
SIGBREAK Ctrl+Break中断
SIGABRT 调用abort导致
2. windows信号的机制~~~
1. 表象
跟踪了SIGSEGV 和 SIGABRT, 发现这两个信号处理线程和程序的主线程是同一个线程
跟踪了SIGINT 和 SIGBREAK, 发现这两个信号处理线程和程序的主线程不是是同一个线程, 而其信号线程的优先级更高
2. 查资料
看MSDN这段话"SIGINT(我觉得应该再加上SIGBREAK) is not supported for any Win32 application. when Ctrl-C interrupt occurs, win32 operating systemd generate a new thread to specifically handle that interrupt. this can cause a sigle-thread application such as one in UNIX to become multithreaded, resulting in unexpected behavior" 意思是在建议在win2应用程序中使用SIGINT和SIGBREAK信号, 因为当这两个信号发生时, OS会专门产生新的线程来处理信号~~~这将导致一个单线程程序表现出多线程程序的特点, 引发未定义行为.
3. 看代码
查看了crt, 发现在调用signal(SIGINT/SIGBREAK, handlefunc)的时候, 如果signal函数发现注册是的SIGINT或者是SIGBREAK信号的话, 就会调用SetConsoleCtrlHandler函数, 把一个名为ctrlevent_capture的函数注册进console的control handler function list(每个console程序都有一个这样的队列用于处理Ctrl-C, Ctrl-Break事件, SetConsoleCtrlHandler可以把一个新的handler function压到队尾, 当事件发生时, 会从队尾开始, 产生线程[线程函数就是压入的handle function]处理事件, 直到某个handle function返回值为true, 如果都不返回true, 就会调用ExitProcess)
所以, 当调用signal(SIGINT/SIGBREAK, handlefunc)发生以下事件
1. 保存handlefunc到合适位置
2. SetConsoleCtrlHandler(ctrlevent_capture, true), 也就是说ctrlevent_capture函数被压入到队列尾部
当信号发生时发生以下事件
1. CreateThread(…, ctrlevent_capture, …)
2. 在ctrlevent_capture的内部, 会取出handlefunc, 并调用
3. ctrlevent_capture返回的是true~~~所以Ctrl-C处理到此为止
综上所述, SIGINT/SIGBREAK的确是OS新产生的线程来处理的
3. 由于本人略看过linux低版本的代码, 所以在这里再比较一下linux和windows信号的区别
1. 这两者完全是两码事, 不可放在同一级别讨论
2. linux信号种类丰富, windows就几种
3. linux信号是操作系统的一种机制, windows信号是CRT库提供的一种功能
4. linux信号的产生和处理不是连续的, 产生SIG的地方只是置位task的sigmask~~~直到系统调用或者中断结束后, 才有可能去处理信号, 也就是信号的发生和处理是异步的
windows信号, 除了SIGINT/SIGBREAK, 其他信号都是类似于
if (注册了SIGXX)
调用handlerfunc
及发生和处理时一起的同步的
4. 看到这些, 相信对windows信号的使用和底层实现的了解就算比较明白了, 希望对大家有帮助