C语言 POSIX线程和信号

a6b3iqyw  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(199)

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

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

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

w8ntj3qf

w8ntj3qf1#

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

正如@zoli2k所指出的,显式指定一个线程来处理您想要处理的所有信号(或者一组线程,每个线程都具有特定的信号职责)是一种很好的技术。

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

我不会说“最好”,但我的建议是:
阻塞main中所有需要的信号,以便所有线程都继承该信号掩码。然后,将特殊的信号接收线程设计为信号驱动的事件循环,将新到达的信号作为一些其他线程内通信分发。
最简单的方法是让线程使用sigwaitinfo or sigtimedwait在循环中接受信号,然后线程以某种方式转换信号,可能是广播pthread_cond_t,唤醒其他具有更多I/O的线程,在特定于应用程序的线程安全队列中排队命令,等等。
或者,该特殊线程可以允许将信号传递到信号处理程序,仅当准备好处理信号时才取消传递的屏蔽。(然而,通过处理程序传递信号往往比通过sigwait系列接收信号更容易出错。)在这种情况下,接收器的信号处理程序执行一些简单且异步信号安全的操作:设置sig_atomic_t标志,调用sigaddset(&signals_i_have_seen_recently, latest_sig)write()一个字节到非阻塞self-pipe,等等。然后,回到其屏蔽的主循环中,如上所述,线程将信号的接收传送到其他线程。
已更新@caf正确地指出sigwait方法更上级。)

fjnneemd

fjnneemd2#

根据POSIX标准,所有线程在系统上都应该以相同的PID出现,使用pthread_sigmask()可以为每个线程定义信号阻塞掩码。
由于每个PID只允许定义一个信号处理程序,我倾向于在一个线程中处理所有信号,如果需要取消正在运行的线程,则发送pthread_cancel()。这是针对pthread_kill()的首选方法,因为它允许为线程定义清理函数。
在一些较旧的系统上,由于缺乏适当的内核支持,运行线程的PID可能与父线程的PID不同。请参阅FAQ了解Linux 2.4上linuxThreads的信号处理。

6yt4nkrj

6yt4nkrj3#

我目前的情况:

  • 信号分为不同的主要类别,其中一些通常应该直接终止进程(SIGILL),而另一些则根本不需要执行任何操作(SIGIO;这两个类不需要任何操作。
  • 有些信号不需要立即处理;类似SIGWINCH的事件可以排队等候,直到方便时为止(就像来自X11的事件一样)。
  • 其中比较棘手的是,你想通过中断正在做的事情来响应它们,但又不至于到了清除线程的程度。特别是,SIGINT在交互模式下应该让事情保持响应。

我仍然需要整理signalsigactionpselectsigwaitsigaltstack,以及一大堆其他POSIX(和非POSIX)API的细节。

fcy6dtqo

fcy6dtqo4#

恕我直言,Unix V信号和posix线程没有很好地混合在一起,Unix V是1970年,POSIX是1980年;)
有取消点,如果你允许信号和pthreads在一个应用程序中,你最终将结束写循环周围的每个调用,这可能会令人惊讶地返回EINTR。
因此,在(少数)必须在Linux或QNX上编写多线程程序的情况下,我所做的是屏蔽所有(除了一个)线程的所有信号。
当一个Unix V信号到达时,进程切换堆栈(在Unix V中,这是你在一个进程中所能得到的最多的并发)。
正如这里的其他帖子所暗示的,现在可能告诉系统哪个posix线程将成为堆栈切换的牺牲品。
一旦你设法让你的信号处理程序线程工作,问题仍然存在,如何将信号信息转换成其他线程可以使用的文明的东西。需要一个线程间通信的基础结构。一个有用的模式是actor模式,其中每个线程都是一些进程内消息传递机制的目标。
因此,您应该尝试将Signal从Signal上下文马歇尔到Signal处理程序线程,然后使用actor模式通信机制将语义上有用的消息发送给那些需要信号相关信息的actor,而不是取消或杀死其他线程(或其他奇怪的事情)。

相关问题