POSIX线程和信号

时间:2010-04-04 16:44:43

标签: c pthreads signals

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

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

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

4 个答案:

答案 0 :(得分:45)

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

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

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

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

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

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

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

更新 @caf正确地指出write方法更胜一筹。)

答案 1 :(得分:13)

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

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

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

答案 2 :(得分:4)

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

有取消点,如果你在一个应用程序中允许信号和pthread,你最终会在每个调用周围编写循环,这可能会令人惊讶地返回EINTR。

所以我在(少数)我需要在Linux或QNX上编程多线程的情况下做的是,掩盖所有(但是一个)线程的所有信号。

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

正如其他帖子提示的那样,现在可以告诉系统哪个posix线程应该是该堆栈切换的受害者。

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

因此,您应该尝试将信号从Signal上下文编组到Signal处理程序线程,然后使用actor模式通信机制发送语义上有用的消息,而不是取消其他线程或杀死它们(或其他奇怪的东西)。那些需要信号相关信息的演员。

答案 3 :(得分:3)

我到目前为止:

  • 信号来自不同的主要类别,其中一些通常应该只是杀死进程(SIGILL),其中一些从不需要做任何事情(SIGIO;无论如何都更容易做异步IO)。这两个课程不需要采取任何行动。
  • 有些信号不需要立即处理;像SIGWINCH这样的人可以排队等候,直到方便(就像来自X11的事件一样)。
  • 狡猾的是那些你想要通过打断你正在做的事情来回应它们但却没有消除线程的程度。特别是,交互模式下的SIGINT应该让事情保持响应。

我仍然需要排序signal vs sigactionpselectsigwaitsigaltstack以及其他一些零碎的东西POSIX(和非POSIX)API。