没有锁的Std::condition_variable

std::condition_variable without a lock

本文关键字:condition variable Std      更新时间:2023-10-16

我正在尝试同步一组线程。这些线程大部分时间都处于睡眠状态,然后醒来执行它们预定的任务。我使用std::thread

不幸的是,当我终止应用程序时,线程阻止它退出。在c#中,我可以将一个线程设置为background,这样它将在应用程序退出时终止。在我看来,c++中似乎没有等效的特性。

所以我决定使用一种事件指示器,让线程在应用程序退出时被唤醒。标准c++ 11 std::condition_variable需要一个唯一的锁,所以我不能使用它,因为我需要两个线程在同一时间唤醒(他们不共享任何资源)。

最终,我决定使用WinApi的CreateEvent + SetEvent + WaitForSingleObject来解决这个问题。

我有一种方法来实现相同的行为只用c++11?

我想要什么:

  1. 一组线程独立工作,通常处于休眠状态(对于不同的线程可能是不同的;
  2. 所有线程检查所有线程是否可用的变量是停止工作的时候了(我称这个变量为IsAliva)。实际上,所有的线程都像这样在循环中旋转:

    while (IsAlive) {
      // Do work
      std::this_thread::sleep_for(...);
    }
    
  3. 线程必须能够同时工作,不能互相阻塞;
  4. 当应用程序关闭,事件上升,它使线程立即唤醒,无论超时;
  5. 唤醒时,它检查IsAlive并退出。

是的,你可以使用条件变量,互斥锁和某种标志的标准c++机制来实现

// Your class or global variables
std::mutex deathLock;
std::condition_variable deathCv;
bool deathTriggered = false;
// Kill Thread runs this code to kill all other threads:
{
    std::lock_guard<std::mutex> lock(deathLock);
    deathTriggered = true;
}
deathCv.notify_all();
// You Worker Threads run this code:
while(true)
{
   ... do work
   // Now wait for 1000 milliseconds or until death is triggered:
   std::unique_lock<std::mutex> lock(deathLock);
   deathCv.wait_for(lock, std::chrono::milliseconds(1000), [](){return deathTriggered;});
   // Check for death
   if(deathTriggered)
   {
      break;
   }
}

请注意,在进入条件之前触发死亡时,此操作会正确运行。你也可以使用wait_for的返回值,但这种方式更容易阅读。此外,虽然它不清楚,多线程睡眠是好的,因为wait_for代码内部解锁unique_lock,同时睡眠和重新获取它来检查条件,也当它返回。

最后,所有的线程都"同时"醒来,因为它们在检查bool标志时被序列化,这只适用于一些指令,然后它们在跳出循环时解锁锁。

在c++11中,你应该能够detach()一个线程,这样它将被视为一个守护线程,这意味着如果应用程序终止,线程将自动停止。