C++。std::condition_variable 和多个等待线程

C++. std::condition_variable and multiple wait-threads

提问人:hdnn 提问时间:8/1/2020 更新时间:8/2/2020 访问量:522

问:

我有一些类,带有 of 成员和方法和 .queuestd::function<void()>PushPop

我想实现加法。当你有一个(谁打电话)和一个(谁打电话)时,这很容易 - 简单就足够了。PushAndWaitUntilExecutedconsumer-threadPopproducer-threadPushstd::condition_variable

但是我的应用程序具有动态数量的线程,它们可以并行执行相同的代码行和调用函数,并等待执行推送的对象。PushAndWaitUntilExecutedconsumer-threadstd::function

A 有传递给的想法,而不仅仅是 ,其中 - ()。然后调用,所有线程将检查执行的线程是否与线程相同。std::pair<uint64_t, std::function<void()>>queuestd::function<void()>uint64_tproducer-thread IDboost::this_thread::get_id()consumer-threadstd::condition_variable::notify_all()std::functionID

是可以的解决方案还是可以实施更好的东西?

C++ 多线程 提升 std

评论

1赞 Daniel Langr 8/1/2020
使用多个条件变量并将它们与函数对象一起存储不是更好吗?然后,任何线程只能等待特定函数(并且在执行其他函数时不会被唤醒)。

答:

2赞 Sam Varshavchik 8/1/2020 #1

这里需要引入的不仅仅是一个条件变量,以避免几个不同的竞争条件。还需要互斥锁和作业完成标志。

在这一点上,用包含此封口以及所有额外行李的小班替换您的行李会变得更干净:std::function<void()>

struct job {
   std::function<void()> implementation;
   std::mutex m;
   std::condition_variable flag;
   bool completed=false;
};

您的队列变成了 s 的队列,而不是 s 的队列,作业在动态范围内构造(当然,因为互斥锁和条件变量不可复制或不可移动,并且这些对象可以从您的两个线程访问)。std::shared_ptr<job>std::function

工作线程完成执行实现后,它会:

  1. 锁定互斥锁。
  2. 设置为 truecompleted
  3. 表示条件变量。

而你的 ,在它执行推送后:PushAndWaitUntilExecuted

  1. 锁定互斥锁
  2. 等待条件变量,直到设置completed

您必须彻底了解,C++ 绝对不能保证,在将新闭包推入作业队列后,某些线程不会立即抓住它,执行它并完成它,然后原始线程(推动它的线程)开始查看条件变量。到现在为止,没有人会再向条件变量发出信号了。如果你在这里只需要一个条件变量,那么你将等待条件变量发出信号,直到我们的太阳爆炸。

这就是为什么你需要的不仅仅是一个条件变量、一个互斥锁和一个显式标志,并使用上述方法来正确处理线程间排序。

这是一种相当经典的常规方法。您应该在每本关于此主题的优秀 C++ 教科书中找到许多类似实现的示例。