是 std::signal 和 std::raise 线程安全的

Are std::signal and std::raise thread-safe?

本文关键字:std 安全 线程 signal raise      更新时间:2023-10-16

>C 和 C++ 标准支持信号的概念。但是,C11 标准说函数 signal() 不能在多线程环境中调用,或者行为是未定义的。但我认为信号机制本质上是针对多线程环境的。

引用C11标准7.14.1.1.7

"在多线程程序中使用此函数会导致未定义的行为。这 实现的行为应像没有库函数调用信号函数一样。

对此有什么解释吗?

以下代码是不言而喻的。

#include <thread>
#include <csignal>
using namespace std;
void SignalHandler(int)
{
    // Which thread context here?
}
void f()
{
    //
    // Running in another thread context.
    //
    raise(SIGINT); // Is this call safe?
}
int main()
{
    //
    // Register the signal handler in main thread context.
    //
    signal(SIGINT, SignalHandler);
    thread(f).join();
}

但我认为信号机制本质上是针对多线程环境的。

我认为这句话是中心误解。 signal() 是一种用于进程间通信的方法,而不是用于线程间通信的方法。线程共享公共内存,因此可以通过互斥锁和控制结构进行通信。进程没有公共内存,必须使用一些显式通信结构(如signal()或文件系统)。

我认为您将特定于进程的信号与线程之间的通信混淆了。如果要在所追求的线程之间共享信息,则可能会在新的 C++11 线程支持库中找到所需的内容。当然,这取决于你真正想做什么。

从我能告诉你的代码来看,你希望一个线程以某种方式"发出"事件信号,并且你希望能够在该事件发出信号时运行一些代码。鉴于此,我会仔细查看线程支持库中的"期货"部分。

C11 标准的声明"在多线程程序中使用此函数会导致未定义的行为",特指函数signal()。所以问题是signal()的使用是否是"在多线程程序中"完成的。

我所知,术语"多线程程序"在 C 标准中没有定义,但我认为它是指已创建多个执行线程但尚未完成的程序。这意味着在示例程序中调用signal()时,该程序不是多线程的,因此程序的行为在此要求下不是未定义的。

(但是C++11要求"所有信号处理程序都应具有C链接"[18.10其他运行时支持[support.runtime] p9]。由于示例程序使用具有C++链接的处理程序,因此行为未定义。


正如其他人指出的那样,信号不适用于线程之间的通信。例如,C 和 C++ 标准甚至没有指定它们在哪个线程上运行。相反,标准库提供了其他用于线程间通信的工具,例如互斥体、原子组学等。

我认为你只是误解了术语未定义的行为,不幸的是,它被重载到意味着"坏事会发生"。在这里,该术语实际上只是意味着它所说的:C 标准没有对在多线程上下文中使用signal的含义做出任何假设。

通常,C标准中的signal/raise接口本身并不是很有用,而只是在其上定义的平台/OS特定事物的占位符。

因此,对于signal和威胁之间的交互,不会给你一个合同。或者另有说明,signal和线程的交互留给平台实现。