【问题标题】:C++. std::condition_variable and multiple wait-threadsC++。 std::condition_variable 和多个等待线程
【发布时间】:2020-11-22 04:42:49
【问题描述】:

我有一些课程,有queuestd::function<void()> 成员和方法PushPop

我想实现加法PushAndWaitUntilExecuted。当你有一个consumer-thread(打电话给Pop)和一个producer-thread(打电话给Push)时,这很容易——只需简单的std::condition_variable就足够了。

但是我的应用程序有动态数量的线程,它们可以通过并行调用 PushAndWaitUntilExecuted 函数来执行相同的代码行,并等到 consumer-thread 执行推送 std::function 对象。

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

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

【问题讨论】:

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

标签: c++ multithreading boost std


【解决方案1】:

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

此时,将std::function<void()> 替换为包含此闭包以及所有额外行李的小类变得更简洁:

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

您的队列变为std::shared_ptr&lt;job&gt;s 的队列,而不是std::functions 的队列,作业在动态范围内构建(当然,互斥锁和条件变量不可复制或移动,并且这些对象可以从你的两个线程访问)。

在您的工作线程完成执行实现后,它:

  1. 锁定互斥体。
  2. completed 设置为true
  3. 向条件变量发出信号。

还有你的PushAndWaitUntilExecuted,在它执行推送之后:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2015-01-28
    • 2020-03-28
    • 2014-03-12
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    • 2020-11-01
    相关资源
    最近更新 更多