我理解唯一的事情,允许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特定功能的解决方案。
答案 0 :(得分: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
被指定为异步信号安全。否则,您的信号处理选项是常见的:经典自管道,sigwait
/ sigwaitinfo
上阻止的信号处理线程,或特定于平台的设施(Linux signalfd
等) )。