【问题标题】:Waking up thread from signal handler从信号处理程序唤醒线程
【发布时间】:2015-09-16 01:13:19
【问题描述】:

我知道,唯一允许 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 特定功能的解决方案。

【问题讨论】:

    标签: c++ linux multithreading signals signal-handling


    【解决方案1】:

    假设您供应商的标准库使用 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 等)。

    【讨论】:

    • 谢谢。这就是我所担心的(尽管我不知道可用 Linux/Posix 机制的完整列表)。我真的希望有一天我们能将信号量纳入标准。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多