POSIX线程和信号
我一直在试图理解POSIX线程和POSIX信号如何交互的复杂性。 我特别感兴趣的是:
- 控制信号传递到哪个线程的最好方法是什么(假设它首先不是致命的)?
- 告诉另一个线程(实际上可能很忙)信号已经到达的最好方法是什么? (我已经知道从信号处理程序中使用pthread条件variables是一个坏主意。)
- 我怎么能安全地处理一个信号发生的信息传递给其他线程? 这是否需要在信号处理程序中发生? (我一般不想杀死其他线程,我需要一个更微妙的方法。)
有关为什么我想要这个参考,我正在研究如何转换TclX包以支持线程,或分裂它,至less使一些有用的部分支持线程。 信号是特别感兴趣的部分之一。
- 控制信号传递到哪个线程的最好方法是什么?
正如@ zoli2k所指出的那样,明确地提名一个线程来处理你想要处理的所有信号(或者一组线程,每个线程都有特定的信号责任),这是一个很好的技术。
- 告诉另一个线程(可能真的很忙)信号已经到达的最好方法是什么?[…]
- 我怎么能安全地处理一个信号发生的信息传递给其他线程? 这是否需要在信号处理程序中发生?
我不会说“最好”,但这是我的build议:
阻止main
所有需要的信号,以便所有线程都inheritance该信号掩码。 然后,将特殊信号接收线程作为信号驱动的事件循环,将新到达的信号作为其它线程内通信进行调度。
最简单的方法是让线程使用sigwaitinfo
或sigtimedwait
在循环中接受信号。 线程然后以某种方式转换信号,或许广播一个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应该让事情变得敏感。
我仍然需要通过signal
, sigaction
, pselect
, sigwait
, sigaltstack
,以及其他一些POSIX(和非POSIX)API的sorting。
- 如何删除和deleteLater关于Qt中的信号和插槽工作?
- 是否有可能以“延迟”方式捕获Ctrl + C信号并运行清理function?
- 什么时候重新连接signalR occour?
- 我怎样才能捕获SIGSEGV(分段错误),并得到在Android上的JNI下的堆栈跟踪?
- 我应该以什么样的顺序发送信号以正常关机?
- SIGSTOP和SIGTSTP有什么区别?
- 通过使用BookSleeve的ConnectionUtils.Connect(),使用SignalR和Redis messagebus进行故障转移
- Bash:运行一个接一个的命令,即使我暂停第一个(Ctrl-z)
- 我可以合并SignalR和RESTful API吗?