是在linux中不可抢占的信号处理程序的执行



我有一个进程p,已向SIGALRM的信号处理程序注册。定时器被设置为周期性地发送信号CCD_ 3以处理CCD_。进程p中也有多个线程在运行。信号处理程序在被触发和执行时是否不可抢占?或者说,是不是信号处理程序的执行不会被进程p中的任何线程中断?

PS:我认为信号处理程序是在内核中执行的(是吗?),内核对用户模式线程是先发制人的?如果错了请纠正我。。。

几乎-不要-在信号处理程序中处理共享数据几乎总是会带来痛苦,处理线程也会让你自己一团糟。

默认情况下,当信号处理程序运行时,信号会被阻塞(至少在linux上,这可能不是普遍正确的),所以至少信号处理程序本身不会被抢占。但是,如果您有多个线程,并且信号在其他线程中没有被阻塞,那么信号处理程序很可能在几个线程中同时运行。

一个线程将接收信号并执行处理程序,哪个线程或多或少是随机的,尽管您可以通过在所有不想处理信号的线程中阻塞信号来控制它。

然而,除了处理信号的线程之外,任何其他线程都可能并行运行。处理信号的线程几乎可以在程序中的任何时候运行信号处理程序(只要信号没有被阻塞)。因此,您需要某种锁定来保护数据。问题是你不能使用任何普通的线程锁定原语,它们不是异步安全的信号。这意味着,如果你试图在信号处理程序中获取pthread_mutex_t,你很容易使程序死锁。

在信号处理程序中唯一可以安全调用的函数是这里列出的函数。关于保护共享数据,您可以使用sigblock()/sigunlock()作为一种保护,确保信号处理程序在您访问共享数据时不会运行,并且信号必须在所有线程中被阻止,否则它将只在一个没有被阻止的线程中运行,走这条路是疯狂的。

在信号处理程序中,几乎唯一可以安全访问的共享数据是sig_atomic_t类型,在实践中,其他类型的基元类型通常也是安全的。

在信号处理程序中,您真正应该做的只是

  • 设置全局标志
  • 如果合适,请在代码中的其他位置检查该标志,并采取行动

  • 有某种主循环,使用select()/poll()或类似方法监视文件描述符中的事件
  • 创建一个管道并在主循环中监视它
  • 将一个字节写入信号处理程序中的管道
  • 运行代码来处理信号,包括在主循环检测到管道上的事件时保护任何共享数据

  • 留一根备用线
  • 阻止所有线程中的给定信号
  • 在调用sigsuspend()时使用备用线程循环,并使用信号掩码确保该信号的传递
  • 运行您的代码,包括保护任何共享数据以处理sigsuspend()返回时的信号

是信号处理程序,当触发并执行,不可抢占?

不,信号处理程序和其他任何用户级函数一样是抢占式的。

我以为信号处理程序被执行了在内核中(是吗?)

不,信号处理程序不是在内核模式下执行的。

从内核模式切换到用户模式时,内核检查进程的挂起信号。如果它发现一个挂起的信号,它会设置用户的堆栈帧,以便在返回到用户模式后,进程开始执行信号处理程序。此后,进程开始在用户模式下执行,像任何其他用户级函数一样执行信号处理程序。执行完成后,进程将切换到内核模式。内核然后恢复进程的原始上下文,执行之前的信号处理时间
所有这些模式切换都不是魔术。内核更改用户堆栈中相应的返回地址。

简短的回答是"否"。

阅读sigaction,尤其是sa_mask字段。默认情况下,即使线程处于信号处理程序中,也可以被另一个信号中断。

此外,短语"被进程p中的任何线程中断"也没有意义。通常,线程是并发运行的;它们不会互相"中断"(除了通过调用pthread_kill())。

相关内容

  • 没有找到相关文章

最新更新