从信号处理程序唤醒线程
我明白关于唯一的事情,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
}
其中至少有两个问题:
notify_one()
(如果我错了,请修改我) 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:
在异步调用的信号处理程序中使用pthread_cond_signal()函数是不安全的。 即使它是安全的,在布尔pthread_cond_wait()的测试之间仍然存在一个无法有效消除的竞争。
互斥和条件变量因此不适合通过从信号处理程序中运行的代码发出信号来释放等待线程。
如果你使用信号灯很舒服, sem_post
被指定为同步信号安全。 否则,您的信号处理选项通常是:经典的自我管理, sigwait
/ sigwaitinfo
上阻塞的信号处理线程,或特定于平台的设施(Linux signalfd
等)。