我在p
的信号处理程序中注册了一个进程SIGALRM
。设置定时器以周期性地将信号SIGALRM
发送到进程p
。在进程p
中还有多个线程在运行。信号处理程序在被触发和执行时是否是不可抢占的?或者说,是否信号处理程序的执行不会被进程p
中的任何线程中断?
PS:我认为信号处理程序是在内核中执行的(是吗?)而内核对于用户模式线程是不受限制的?纠正我,如果这是错的......
答案 0 :(得分:17)
非常 - 不 - 在信号处理程序中处理共享数据几乎总会导致痛苦的世界,同时处理线程并且让你自己弄得一团糟。
默认情况下,信号处理程序运行时会阻塞信号(至少在linux上,这可能不是普遍存在的),所以至少信号处理程序不会被自己抢占。但是,如果你有多个线程,并且信号没有在其他线程中被阻塞,那么信号处理程序很可能会在多个线程中同时运行。
一个线程将接收信号并执行处理程序,它或多或少是随机的线程,尽管你可以通过阻止你不想处理信号的所有线程中的信号来控制它。
但是,处理信号的任何其他线程都可以并行运行。处理信号的线程可以在程序中的几乎任何点运行信号处理程序(只要信号没有被阻塞)。因此,您需要某种锁定来保护该数据。问题是你不能使用任何普通的线程锁定原语,它们不是信号异步安全。这意味着你,例如尝试在信号处理程序中获取pthread_mutex_t,您很容易使程序死锁。
您可以在信号处理程序中安全调用的唯一函数是here列出的函数。 关于保护共享数据,您可以使用sigblock()/ sigunblock()作为一种保护,确保在您访问共享数据时信号处理程序不会运行 - 并且信号必须在所有线程,否则它只会在其中一个没有被阻塞的线程中运行 - 走这条路是疯狂的。
您可以在信号处理程序中安全访问的唯一共享数据是sig_atomic_t
类型,实际上其他类型的原始类型通常也是安全的。
你在信号处理程序中真正应该做的只是
或者
或者
答案 1 :(得分:5)
是信号处理程序 触发并执行, 未预占?
不,信号处理程序像任何其他用户级功能一样是抢占式的。
我认为信号处理程序已执行 在内核中(是吗?)
不,信号处理程序不在内核模式下执行。
内核在从内核模式切换到用户模式时检查进程的挂起信号。如果它找到待处理信号,则设置用户的堆栈帧,使得在返回用户模式之后,该过程开始执行信号处理程序。此后,进程在用户模式下开始执行,执行信号处理程序,就像任何其他用户级别函数一样。执行完成后,进程切换到内核模式。然后内核恢复进程的原始上下文,在信号处理之前执行 所有这种模式切换都不是魔术。内核更改用户堆栈中的相应返回地址。
答案 2 :(得分:2)
简短的回答是“不”。
阅读sigaction,尤其是sa_mask字段。默认情况下,即使在信号处理程序中,您的线程也可能被另一个信号中断。
此外,短语“由进程p中的任何线程中断”没有意义。通常,线程并发运行;它们不会相互“中断”(除非通过调用pthread_kill())。