c++信号处理程序可以唤醒线程

c++ signal handler can wake a thread?

本文关键字:唤醒 线程 信号处理 程序 c++      更新时间:2023-10-16

由于c++信号处理程序应该只访问volatile std::sig_atomic_t或std::atomic(自c++ 11起),是否有可能让线程休眠并唤醒它?

std::atomic_bool exit_now(false);
void signal_handler(int signal)
{
  exit_now=true;
}
int main() {
      std::signal(SIGINT, signal_handler);
      A a;
      B b;
      a.RunAsync();
      b.RunAsync();
      while(!exit_now)
          std::this_thread::sleep_for(std::chrono::seconds(1));
      a.Stop();
      b.Stop();
      return 0;
}

在这种情况下,A和B::RunAsync()都在其他线程上做它们的业务,直到我调用::Stop(),所以我唯一的选择是在主线程上忙等待(有或没有预定义的睡眠周期)。

理想情况下,我希望主线程在发出信号之前一直休眠,可能会使用条件变量,但这样做看起来是非法的。

我建议(阻塞信号和)使用sigwait(2)在主线程中同步等待信号,然后您完全规避了必须从信号处理程序到线程进行通信的问题。

您需要的是一种以异步信号安全的方式唤醒线程的方法。

在Linux中,我更喜欢的方法是使用POSIX信号量。请记住,这可能无法移植到其他操作系统,因为操作系统不需要POSIX信号量才能被认为是POSIX兼容的。
  1. 在注册信号处理器之前:
  // signalSemaphore is a global variable
  if (sem_init(&signalSemaphore, 0, 0)) {
    std::cerr << "Unable to initialise semaphore: " << strerror(errno);
    return 1;
  }
  • 从你想要唤醒的线程:
  • while(sem_wait(signalSemaphore)) {
      if(errno != EINTR) {
        // call can be interrupted, so if the error is EINTR we ignore it
        std::cerr << "Error waiting for signal semaphore: " << strerror(errno);
      }
    }
    
  • 从信号处理程序,将信号量调到1。这将解锁sem_wait()调用:
  • void signalHandler(int signal) {
      sem_post(&signalSemaphore);
    }
    

    或者,使用管道也是一种选择,因为read()write()系统调用也是异步信号安全的,管道是一种更可移植的机制。这里有一个关于如何做到这一点的例子:我如何以一种异步信号安全的方式唤醒macOS中的线程?