POSIX线程和信号

Don*_*ows 76 c signals pthreads

我一直在努力理解POSIX线程和POSIX信号如何相互作用的复杂性.特别是,我对以下内容感兴趣:

  • 什么是控制信号传递到哪个线程的最佳方法(假设它首先不是致命的)?
  • 告诉另一个线程(可能实际上很忙)信号已经到达的最佳方法是什么?(我已经知道从信号处理程序使用pthread条件变量是一个坏主意.)
  • 如何安全地处理将信号发生的信息传递给其他线程?这是否需要在信号处理程序中发生?(我一般不想杀死其他线程;我需要一个更微妙的方法.)

关于为什么我想要这个的参考,我正在研究如何将TclX包转换为支持线程,或者将其拆分并至少使一些有用的部分支持线程.信号是特别感兴趣的部分之一.

pil*_*row 46

  • 什么是控制信号传递到哪个线程的最佳方法?

正如@ zoli2k所指出的那样,明确地指定一个线程来处理你想要处理的所有信号(或者每个具有特定信号职责的一组线程),这是一种很好的技术.

  • 告诉另一个线程(可能实际上很忙)信号已经到达的最佳方法是什么?[...]
  • 如何安全地处理将信号发生的信息传递给其他线程?这是否需要在信号处理程序中发生?

我不会说"最好",但这是我的建议:

阻止所有所需的信号main,以便所有线程都继承该信号掩码.然后,将特殊信号接收线程设计为信号驱动事件循环,将新到达的信号作为一些其他线程内通信进行分派.

最简单的方法是让线程使用sigwaitinfosigtimedwait在循环中接受信号.然后线程以某种方式转换信号,可能是广播pthread_cond_t,用更多的I/O唤醒其他线程,在特定于应用程序的线程安全队列中排队命令,无论如何.

或者,特殊线程可以允许将信号传递到信号处理程序,仅在准备好处理信号时取消屏蔽以便传送.(sigwait然而,通过处理程序传递信号往往比通过系列接收信号更容易出错.)在这种情况下,接收器的信号处理程序执行一些简单且异步信号安全的操作:设置sig_atomic_t标志,调用sigaddset(&signals_i_have_seen_recently, latest_sig),write()一个字节到非阻塞自管等.然后,回到它掩蔽主循环中,线程通信接收到信号,以如上述的其它线程.

(更新 @caf正确地指出sigwait方法是优越的.)


zol*_*i2k 13

根据POSIX标准,所有线程应该在系统上显示相同的PID,并且使用pthread_sigmask()您可以为每个线程定义信号阻塞掩码.

由于允许每个PID只定义一个信号处理程序,我更喜欢处理一个线程中的所有信号,并pthread_cancel()在需要取消正在运行的线程时发送.它是首选的方法,pthread_kill()因为它允许为线程定​​义清理函数.

在一些较旧的系统上,由于缺乏适当的内核支持,正在运行的线程可能与父线程的PID具有不同的PID.有关在Linux 2.4上使用linuxThreads进行信号处理的常见问题解答.