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

8

我知道,在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
}

这至少存在两个问题:

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

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

请注意,即使我的程序只有一个线程,我也将我的问题标记为多线程,因为它涉及线程控制原语。如果在标准C++中没有解决方案,我愿意接受使用Linux/POSIX特定函数的解决方案。

1个回答

9
假设您的供应商标准库使用函数来实现C++11条件变量(libstdc++ 和 libc++都是这样做的),函数不是异步信号安全的,因此不能从信号处理程序中调用。根据http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_broadcast.html,即使在信号处理程序中使用 pthread_cond_signal() 函数是安全的,仍然会存在无法有效消除的pthread_cond_wait()布尔测试之间的竞争。因此,互斥锁和条件变量不适合通过信号处理程序中的代码发出信号以释放等待线程。如果您熟悉使用信号量,则sem_post被指定为异步信号安全。否则,您的信号处理选项与往常一样:经典的自管道、阻塞于sigwait/sigwaitinfo的信号处理线程,或平台特定的功能(Linux中的signalfd等)。

谢谢。这正是我担心的(尽管我不知道可用的Linux / Posix机制的全面列表)。我真的希望有一天我们能将信号量纳入标准。 - MikeMB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接