从信号处理程序中唤醒线程

Waking up thread from signal handler

我知道 ISO/C++11 中的信号处理程序唯一允许做的事情是读取或写入无锁原子变量或 volatile sig_atomic_t(我相信,POSIX 稍微宽松一点,允许调用一堆系统函数)。

我想知道是否有任何方法可以唤醒正在等待条件变量的线程。 IE。类似于:

#include <mutex>
#include <atomic>
#include <condition_variable>


std::mutex mux;
std::condition_variable cv;

std::atomic_bool doWait{ true };

void signalHandler(int){
    doWait = false;
    cv.notify_one();
}

int main() {
    //register signal handler
    //Do some stuff

    {//wait until signal arrived
        std::unique_lock<std::mutex> ul(mux);
        cv.wait(ul, []{return !doWait; });
    }

    //Do some more stuff
}

其中至少有两个问题:

  1. 我相信,我不允许在信号处理程序中调用 notify_one()(如果我错了请纠正我)
  2. 信号可能恰好在检查 doWait 和线程进入休眠之间到达,因此它永远不会醒来(显然,我无法在 signalHander 中锁定互斥锁来避免这种情况) .

到目前为止,我能看到的唯一解决方案是在 doWait 变量上实现忙等待(可能在每次迭代中休眠几毫秒),这让我觉得效率很低。

请注意,尽管我上面的程序只有一个线程,但我用多线程标记了我的问题,因为它是关于线程控制原语的。如果标准 c++ 中没有解决方案,我愿意接受使用 Linux/POSIX 特定函数的解决方案。

假设您的供应商的标准库使用 pthread_cond_* 函数来实现 C++11 条件变量(libstdc++ 和 libc++ 这样做),pthread_cond_* 函数不是异步信号安全的,所以不能从信号处理程序调用。

来自http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_broadcast.html

It is not safe to use the pthread_cond_signal() function in a signal handler that is invoked asynchronously. Even if it were safe, there would still be a race between the test of the Boolean pthread_cond_wait() that could not be efficiently eliminated.

Mutexes and condition variables are thus not suitable for releasing a waiting thread by signaling from code running in a signal handler.

如果您习惯使用信号量,sem_post 被指定为异步信号安全。否则,您的信号处理选项是通常的:经典的自管道,阻塞在 sigwait/sigwaitinfo 上的信号处理线程,或特定于平台的工具(Linux signalfd, 等等).