C语言 POSIX 线程和信号
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2575106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
POSIX threads and signals
提问by Donal Fellows
I've been trying to understand the intricacies of how POSIX threads and POSIX signals interact. In particular, I'm interested in:
我一直试图了解 POSIX 线程和 POSIX 信号如何交互的复杂性。我特别感兴趣的是:
- What's the best way to control which thread a signal is delivered to (assuming it isn't fatal in the first place)?
- What is the best way to tell another thread (that might actually be busy) that the signal has arrived? (I already know that it's a bad idea to be using pthread condition variables from a signal handler.)
- How can I safely handle passing the information that a signal has occurred to other threads? Does this need to happen in the signal handler? (I do not in general want to kill the other threads; I need a far subtler approach.)
- 控制信号传递到哪个线程的最佳方法是什么(假设它首先不是致命的)?
- 告诉另一个线程(实际上可能很忙)信号已经到达的最佳方法是什么?(我已经知道从信号处理程序中使用 pthread 条件变量是一个坏主意。)
- 如何安全地处理将发生信号的信息传递给其他线程?这是否需要在信号处理程序中发生?(我一般不想杀死其他线程;我需要一种更微妙的方法。)
For reference about why I want this, I'm researching how to convert the TclXpackage to support threads, or to split it up and at least make some useful parts support threads. Signals are one of those parts that is of particular interest.
关于我为什么想要这个的参考,我正在研究如何将TclX包转换为支持线程,或者将其拆分并至少制作一些有用的部分来支持线程。信号是那些特别令人感兴趣的部分之一。
采纳答案by pilcrow
- What's the best way to control which thread a signal is delivered to?
- 控制信号传递到哪个线程的最佳方法是什么?
As @zoli2k indicated, explicitly nominating a single thread to handle all signals you want handled (or a set of threads each with specific signal responsibilities), is a good technique.
正如@zoli2k 指出的那样,明确指定一个线程来处理您想要处理的所有信号(或一组线程,每个线程都具有特定的信号职责),是一种很好的技术。
- What is the best way to tell another thread (that might actually be busy) that the signal has arrived?[...]
- How can I safely handle passing the information that a signal has occurred to other threads? Does this need to happen in the signal handler?
- 告诉另一个线程(实际上可能很忙)信号已经到达的最佳方法是什么?[...]
- 如何安全地处理将发生信号的信息传递给其他线程?这是否需要在信号处理程序中发生?
I won't say "best," but here's my recommendation:
我不会说“最好”,但这是我的建议:
Block all desired signals in main, so that all threads are inherit that signal mask. Then, fashion the special signal receiving thread as a signal-driven event loop, dispatching newly arrived signals as some other intra-thread communication.
在 中阻塞所有需要的信号main,以便所有线程都继承该信号掩码。然后,将特殊的信号接收线程设计为信号驱动的事件循环,将新到达的信号作为其他一些线程内通信进行调度。
The simplest way to do this is to have the thread accept signals in a loop using sigwaitinfoor sigtimedwait. The thread then converts the signals somehow, perhaps broadcasting a pthread_cond_t, waking up other threads with more I/O, enqueuing a command in an application-specific thread-safe queue, whatever.
最简单的方法是让线程在循环中使用sigwaitinfoorsigtimedwait接受信号。然后线程以某种方式转换信号,可能广播 a pthread_cond_t,唤醒具有更多 I/O 的其他线程,将命令排入特定于应用程序的线程安全队列,等等。
Alternatively, the special thread could allow signals to be delivered to a signal handler, unmasking for delivery only when ready to handle signals. (Signal delivery via handlers tends to be more error-prone than signal acceptance via the sigwaitfamily, however.) In this case, the receiver's signal handler performs some simple and async-signal-safe action: setting sig_atomic_tflags, calling sigaddset(&signals_i_have_seen_recently, latest_sig), write() a byte to a non-blocking self-pipe, etc. Then, back in its masked main loop, the thread communicates receipt of the signal to other threads as above.
或者,特殊线程可以允许将信号传递给信号处理程序,仅在准备好处理信号时才取消屏蔽以进行传递。(sigwait然而,通过处理程序传递信号往往比通过家族接受信号更容易出错。)在这种情况下,接收者的信号处理程序执行一些简单的异步信号安全操作:设置sig_atomic_t标志,调用sigaddset(&signals_i_have_seen_recently, latest_sig), write() 一个字节到非阻塞自管道等。然后,回到其屏蔽的主循环中,线程将信号的接收传达给其他线程,如上所述。
(UPDATED@caf rightly points out that sigwaitapproaches are superior.)
(更新的@caf 正确地指出sigwait方法更胜一筹。)
回答by zoli2k
According to the POSIX standard all threads should appear with the same PID on the system and using pthread_sigmask()you can define the signal blocking mask for every thread.
根据 POSIX 标准,所有线程都应该在系统上显示为相同的 PID,并且使用pthread_sigmask()您可以为每个线程定义信号阻塞掩码。
Since it is allowed to define only one signal handler per PID, I prefer to handle all signals in one thread and send pthread_cancel()if a running thread need to be cancelled. It is the preferred way against pthread_kill()since it allows to define cleanup functions for the threads.
由于允许每个 PID 只定义一个信号处理程序,我更喜欢在一个线程中处理所有信号,并pthread_cancel()在需要取消正在运行的线程时发送。这是首选方式,pthread_kill()因为它允许为线程定义清理函数。
On some older systems, because of the lack of proper kernel support, the running threads may have different PID from the parent thread's PID. See FAQ for signal handling with linuxThreads on Linux 2.4.
在一些较旧的系统上,由于缺乏适当的内核支持,正在运行的线程可能具有与父线程的 PID 不同的 PID。有关Linux 2.4 上使用linuxThreads 的信号处理,请参阅 FAQ 。
回答by Donal Fellows
Where I'm at so far:
到目前为止我在哪里:
- Signals come in different major classes, some of which should typically just kill the process anyway (SIGILL) and some of which never need anything doing (SIGIO; easier to just do async IO right anyway). Those two classes need no action.
- Some signals don't need to be dealt with immediately; the likes of SIGWINCH can be queued up until it is convenient (just like an event from X11).
- The tricky ones are the ones where you want to respond to them by interrupting what you're doing but without going to the extent of wiping out a thread. In particular, SIGINT in interactive mode ought to leave things responsive.
- 信号有不同的主要类别,其中一些通常应该只是终止进程(SIGILL),而其中一些永远不需要做任何事情(SIGIO;无论如何都更容易执行异步 IO)。这两个类不需要任何操作。
- 有些信号不需要立即处理;SIGWINCH 之类的可以排队,直到方便为止(就像来自 X11 的事件)。
- 棘手的是你想通过中断你正在做的事情来回应他们,但又不想抹掉一个线程。特别是,交互模式下的 SIGINT 应该让事情保持响应。
I've still got to sort through signalvs sigaction, pselect, sigwait, sigaltstack, and a whole bunch of other bits and pieces of POSIX (and non-POSIX) API.
我仍然需要对signalvs sigaction、pselect、sigwait、sigaltstack和一大堆其他的 POSIX(和非 POSIX)API 进行分类。
回答by user2173833
IMHO, Unix V signals and posix threads do not mix well. Unix V is 1970. POSIX is 1980 ;)
恕我直言,Unix V 信号和 posix 线程不能很好地混合。Unix V 是 1970 年。POSIX 是 1980 年;)
There are cancellation Points and if you allow signals and pthreads in one application, you will eventually end up writing Loops around each call, which can surprisingly return EINTR.
有取消点,如果您允许在一个应用程序中使用信号和 pthread,您最终会围绕每个调用编写循环,这可能会令人惊讶地返回 EINTR。
So what I did in the (few) cases where I had to program multithreaded on Linux or QNX was, to mask out all signals for all (but one) threads.
因此,在我不得不在 Linux 或 QNX 上对多线程进行编程的(少数)情况下,我所做的是屏蔽所有(但一个)线程的所有信号。
When a Unix V Signal arrives, the process Switches the stack (that was as much concurrency in Unix V as you could get within a process).
当 Unix V 信号到达时,进程会切换堆栈(在 Unix V 中,您可以在进程中获得尽可能多的并发性)。
As the other posts here hint, it might be possible now, to tell the System, which posix thread shall be the victim of that stack switching.
正如这里的其他帖子所暗示的那样,现在可能可以告诉系统,哪个 posix 线程将成为该堆栈切换的牺牲品。
Once, you managed to get your Signal handler thread working, the question remains, how to transform the signal information to something civilized, other threads can use. An infrastructure for inter-thread communications is required. One pattern, useful is the actor pattern, where each of your threads is a target for some in-process Messaging mechanism.
有一次,您设法让 Signal 处理程序线程工作,但问题仍然存在,如何将信号信息转换为其他线程可以使用的文明信息。需要用于线程间通信的基础设施。一种有用的模式是参与者模式,其中每个线程都是某些进程内消息传递机制的目标。
So, instead of canceling other threads or killing them (or other weird stuff), you should try to marshall the Signal from the Signal context to your Signal handler thread, then use your actor pattern communications mechanisms to send semantically useful messages to those actors, who need the signal related Information.
因此,与其取消其他线程或杀死它们(或其他奇怪的东西),您应该尝试将 Signal 从 Signal 上下文编组到您的 Signal 处理程序线程,然后使用您的 actor 模式通信机制向这些 actor 发送语义上有用的消息,谁需要信号相关的信息。

