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