POSIX线程和信号

我一直在试图理解POSIX线程和POSIX信号如何交互的复杂性。 我特别感兴趣的是:

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

有关为什么我想要这个参考,我正在研究如何转换TclX包以支持线程,或分裂它,至less使一些有用的部分支持线程。 信号是特别感兴趣的部分之一。

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

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

  • 告诉另一个线程(可能真的很忙)信号已经到达的最好方法是什么?[…]
  • 我怎么能安全地处理一个信号发生的信息传递给其他线程? 这是否需要在信号处理程序中发生?

我不会说“最好”,但这是我的build议:

阻止main所有需要的信号,以便所有线程都inheritance该信号掩码。 然后,将特殊信号接收线程作为信号驱动的事件循环,将新到达的信号作为其它线程内通信进行调度。

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

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

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

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

由于每个PID只允许定义一个信号处理程序,因此如果需要取消正在运行的线程,我宁愿处理一个线程中的所有信号,并发送pthread_cancel() 。 这是针对pthread_kill()的首选方法,因为它允许为线程定​​义清理函数。

在一些较老的系统上,由于缺乏适当的内核支持,正在运行的线程可能与父线程的PID具有不同的PID。 请参阅Linux 2.4上的linuxThreads的信号处理FAQ。

恕我直言,Unix V信号和posix线程不能很好地混合。 Unix V是1970. POSIX是1980;)

有取消点,如果你允许在一个应用程序中的信号和pthreads,你最终将最终在每个电话周围写循环,这可以令人惊讶地返回EINTR。

所以我在less数情况下为Linux或QNX编写multithreading程序所做的事情是屏蔽所有(但是一个)线程的所有信号。

当一个Unix V信号到达时,进程切换堆栈(在一个进程中可以得到与Unix V同样多的并发)。

正如其他post提示的那样,现在可能告诉系统,哪个posix线程将成为堆栈切换的受害者。

有一次,你设法让你的信号处理线程工作,问题仍然存在,如何将信号信息转换为文明的,其他线程可以使用。 用于线程间通信的基础结构是必需的。 一种模式,有用的是演员模式,其中每个线程是一些进程内消息传递机制的目标。

所以,不要取消其他线程或杀死它们(或其他奇怪的东西),你应该尝试将Signal从Signal上下文中放到Signal处理线程中,然后使用你的actor模式通信机制将语义上有用的消息发送给这些actor,谁需要信号相关的信息。

我到目前为止:

  • 信号来自不同的主要类,其中一些通常应该杀死进程(SIGILL),其中一些从来不需要做任何事情(SIGIO;反之更容易执行asynchronousIO)。 这两个阶级不需要采取行动。
  • 有些信号不需要立即处理; SIGWINCH等可以排队,直到方便(就像来自X11的事件一样)。
  • 那些棘手的问题是你想通过打断你正在做的事情来回应他们的问题,而不会去掉一个线程。 特别是交互模式下的SIGINT应该让事情变得敏感。

我仍然需要通过signalsigactionpselectsigwaitsigaltstack ,以及其他一些POSIX(和非POSIX)API的sorting。