首页 > 解决方案 > 使用单个条件变量暂停多个线程

问题描述

我有一个启动 N 个线程(异步/未来)的程序。我希望主线程设置一些数据,然后所有线程都应该去,而主线程等待所有其他线程完成,然后这需要循环。

我有自动取款机是这样的

int main()
{  
    //Start N new threads (std::future/std::async)
    while(condition)
    {
       //Set Up Data Here
       //Send Data to threads
       {
           std::lock_guard<std::mutex> lock(mrun);
           bRun = true;

       }
       run.notify_all();
       //Wait for threads
       {
           std::unique_lock<std::mutex> lock(mrun);
           run.wait(lock, [] {return bDone; });
       }
       //Reset bools
       bRun = false;
       bDone = false;
    }
    //Get results from futures once complete
}

int thread()
{
    while(otherCondition)
    {
       std::unique_lock<std::mutex> lock(mrun);
       run.wait(lock, [] {return bRun; });
       bDone = true;
       //Do thread stuff here
       lock.unlock();
       run.notify_all();
    }
}

但是我看不到任何主线程或其他线程在等待对方的迹象!知道我做错了什么或者我该怎么做吗?

标签: c++multithreadingasynchronouscondition-variable

解决方案


有几个问题。首先,您在bDone第一个工作人员醒来后立即进行设置。因此主线程立即唤醒并开始准备下一个数据集。您希望主线程等待所有工作人员完成数据处理。其次,当工作人员完成处理时,它会循环并立即检查bRun. 但它无法判断是否bRun == true意味着下一个数据集已准备好或最后一个数据集是否已准备好。您想等待下一个数据集。

像这样的东西应该工作:

std::mutex mrun;
std::condition_variable dataReady;
std::condition_variable workComplete;

int nCurrentIteration = 0;
int nWorkerCount = 0;

int main()
{
  //Start N new threads (std::future/std::async)
  while(condition)
  {
    //Set Up Data Here
    //Send Data to threads
    {
       std::lock_guard<std::mutex> lock(mrun);
       nWorkerCount = N;
       ++nCurrentIteration;
    }
    dataReady.notify_all();
    //Wait for threads
    {
       std::unique_lock<std::mutex> lock(mrun);
       workComplete.wait(lock, [] { return nWorkerCount == 0; });
    }
  }
  //Get results from futures once complete
}

int thread()
{
  int nNextIteration == 1;

  while(otherCondition)
  {
    std::unique_lock<std::mutex> lock(mrun);
    dataReady.wait(lock, [&nNextIteration] { return nCurrentIteration==nNextIteration; });
    lock.unlock();

    ++nNextIteration;

    //Do thread stuff here

    lock.lock();
    if (--nWorkerCount == 0)
    {
      lock.unlock();
      workComplete.notify_one();
    }
  }
}

请注意,此解决方案并不完整。如果一个worker遇到异常,那么主线程就会挂起(因为死掉的worker永远不会reduce nWorkerCount)。您可能需要一种策略来处理这种情况。

顺便说一下,这种模式称为 a barrier


推荐阅读