Linux - 信号
参考文档
- 24.2 Standard Signals
- 深入理解Linux内核-信号
- 进入用户空间执行用户自定义的信号处理函数时,会创建一个临时的用户空间栈
常见信号
SIGKILL:不可被捕获、忽略,取值为9SIGINT:可以被捕获、忽略、阻塞,取值为2,由ctrl+c产生SIGTERM:可以被捕获、忽略、阻塞,kill命令默认发这个信号SIGQUIT):类似SIGINT,由ctrl+\产生SIGSTOP:不可被忽略、捕获,停止程序SIGSTP:可以被捕获、忽略、阻塞,由ctrl+z产生SIGCONT:恢复进程的执行,不能被捕获或忽略
同步/异步信号
同步信号的例子包括非法存储器访问以及除法除以0.如果一个正在运行的程序执行了任一操作,一个信号就会生成。
同步信号传递到执行操作而导致产生信号的同一进程(这就是被认为是同步的原因)
当一个信号由运行的进程之外的事件产生,那么进程就会异步的接收这个信号。这样的例子包括用特定的击键结束进程(比如ctrl + c)或者是定时器到期。通常,信号被发送到另一个进程
信号的响应
在进程由内核态返回用户态时,会在在内核态检查当前是否有信号待处理,如果有的话,就会进入信号响应流程
多线程环境下信号传递
单线程程序的信号处理比较直接,信号总是发给进程。
不过,对于多线程程序,发送信号比较复杂,因为进程可能有多个线程,应该将信号发给谁呢??
一般来说,存在以下选项:
- 将信号发送到信号所应用的线程。
- 将信号传递到进程中的每个线程。
- 将信号传递给进程中的某些线程。
- 指定一个特定的线程来接收该进程的所有信号。
传递信号的方法取决于所产生的信号的类型。例如,需要将同步信号传递给引起信号的线程,而不需要传递给进程中的其他线程。然而,对于异步信号,情况就不那么清楚。一些异步信号——例如终止进程的信号(例如ctrl + c)——应该发送到所有线程。
发送信号的标准UNIX函数是:
1 | |
该函数指定哪个特定的信号(即signal参数)被发送到指定的进程上(即pid参数)。大多数多线程版本的UNIX允许一个线程指定它将接受哪个信号,它将会阻止哪个信号。因此,在某些情况下,异步信号只能传递给那些没有阻止它的线程。但是,因为信号只需要处理一次,所以信号通常只发送到发现的第一个不阻止它的线程上[但是不可捕获、忽略的信号会被发送给每一个线程并执行]。POSIX Pthreads提供了以下功能,它允许将信号传递到指定的线程(tid):
1 | |
使用指南
线程的信号屏蔽字是per_thread的,因此通过信号屏蔽关键字,只有一个线程没有屏蔽该信号,其它线程均屏蔽该信号。达到控制某个线程处理某个信号的目的。
但是对于那些不能被屏蔽的信号怎么办?