15

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();
}
4

4 回答 4

16

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

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

于 2013-01-30T21:04:10.240 回答
4

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

根据我对您的代码的了解,您希望线程以某种方式“发出信号”,并且您希望能够在发出该事件的信号时运行一些代码。鉴于此,我将仔细研究线程支持库中的 Futures 部分。

于 2013-01-30T21:34:23.023 回答
2

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

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

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


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

于 2013-01-30T21:44:42.167 回答
1

我认为您只是误解了undefined behavior一词,不幸的是,该词过多地表示“将发生坏事”。这里的术语实际上只是它所说的意思:C 标准没有对signal在多线程上下文中使用的含义做出任何假设。

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

So for an interaction between signal and threats doesn't give you a contract. Or stated otherwise, the interaction of signal and threads is left to the platform implementation.

于 2016-06-18T10:31:08.900 回答