从信号处理程序唤醒线程

Mik*_*eMB 6 c++ linux multithreading signals signal-handling

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

我想知道,如果有任何办法,唤醒正在等待条件变量的线程.就像这样:

#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
}
Run Code Online (Sandbox Code Playgroud)

其中至少有两个问题:

  1. 我相信,我不允许打电话notify_one()给信号处理程序(如果我错了,请告诉我)
  2. 信号可以在检查doWait和线程进入休眠之间到达,因此它永远不会被唤醒(显然,我无法锁定signalHander中的互斥锁以避免这种情况).

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

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

eca*_*mur 5

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

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

在异步调用的信号处理程序中使用pthread_cond_signal()函数是不安全的.即使它是安全的,布尔pthread_cond_wait()的测试之间仍然会有一场无法有效消除的竞赛.

因此,互斥量和条件变量不适合通过从信号处理程序中运行的代码发出信号来释放等待线程.

如果您习惯使用信号量,sem_post则指定为async-signal-safe.否则,您的信号处理选项通常是:经典的自管道,阻塞在sigwait/ 上的信号处理线程sigwaitinfo,或特定于平台的设施(Linux signalfd等).