【问题标题】:Using mutexes in signal handers在信号处理程序中使用互斥锁
【发布时间】:2020-07-03 07:22:37
【问题描述】:

我有一个多线程应用程序,需要在中断、终止等信号时正常停止它。

这里有一个sn-p来说明逻辑的相关部分。

std::atomic_bool running = true;
std::mutex mutex;
std::condition_variable condition;

void signal_handler(int signal)
{
  // in another thread `[&]() { return !running || something_to_do_conditon; } == false`
  // what means continue to wait
  running = false;
  condition.notify_one();
  // another thread goes to sleep
}

void run() {
    while(true) {
      std::unique_lock lock(mutex);
      condition.wait_for(lock, std::chrono::hours(1), [&]() { return !running || something_to_do_conditon; });

      if (!running) {
          return;
      }

      // do smth
    }
}

int main()
{
  // Install a signal handler
  std::signal(SIGINT, signal_handler);
  std::signal(SIGTERM, signal_handler);

  std::thread thread(run);
  thread.join();
}

正如您在signal_handler 中看到的那样,即使running 设置为false,也可能会通知condition,仍然存在一种情况(使用内联cmets 描述),其中线程睡1小时。发生这种情况是因为 running 变量周围没有互斥锁。这允许线程在设置变量之前锁定互斥锁并检查条件。如果我添加类似

  {
      std::lock_guard<std::mutex> lock(mutex);
      running = false;
  }

在将要避免的处理程序中。

那么问题是如何使用(是否可能)互斥锁而不会出现潜在的死锁或任何其他问题。从信号中削弱睡眠线程的任何其他技巧。

【问题讨论】:

标签: c++ linux multithreading pthreads signals


【解决方案1】:

在 pthreads 程序中处理信号的一种可靠方法是屏蔽您希望在每个线程中处理的所有信号,并创建一个专用的信号处理线程来循环调用 sigwaitinfo()(或 sigtimedwait())。

然后,信号处理线程可以使用普通的互斥保护共享变量和pthread_cond_signal() / pthread_cond_broadcast() 唤醒来通知其他线程收到的信号。

在您的示例中,专用信号处理线程可以在更改 running 标志之前安全地锁定互斥锁,因为它只是在普通线程上下文中,而不是信号处理程序。

【讨论】:

  • 信号处理程序中的互斥锁不是一个好主意,因为如果另一个信号会出现,它可能会重新进入处理程序导致死锁。
  • @teoring:是的 - 更一般地说,互斥锁函数不是异步信号安全的,因此在这种情况下使用它们是错误的。这个答案是关于使用普通线程上下文中的线程使用sigwaitinfo()(而不是使用已安装的信号处理函数)处理信号,这确实允许安全使用互斥函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 2016-05-25
  • 2011-10-11
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
相关资源
最近更新 更多