【问题标题】:Synchronizing three threads with Condition Variable使用条件变量同步三个线程
【发布时间】:2014-05-13 14:57:27
【问题描述】:

我的应用程序中有三个线程,第一个线程需要等待其他两个线程的数据准备好。两个线程同时准备数据。 为了做到这一点,我在 C++ 中使用条件变量如下:

boost::mutex mut;       
boost::condition_variable cond;     

线程1:

    bool check_data_received()
    {
         return (data1_received && data2_received);
    }

    // Wait until socket data has arrived
    boost::unique_lock<boost::mutex> lock(mut);
    if (!cond.timed_wait(lock, boost::posix_time::milliseconds(200),
        boost::bind(&check_data_received)))
    {

    }

线程2:

    {
        boost::lock_guard<boost::mutex> lock(mut);
        data1_received = true;
    }
    cond.notify_one();

线程3:

    {
        boost::lock_guard<boost::mutex> lock(mut);
        data2_received = true;
    }
    cond.notify_one();

所以我的问题是这样做是否正确,或者有没有更有效的方法?我正在寻找最优化的等待方式。

【问题讨论】:

  • “最优化的方式”来“等待”是一个令人惊讶的强大矛盾:)
  • @sehe 我知道等待是不好的,并且会影响工作的并行性。这就是为什么我想知道,如果有另一种方法来实现我想要的:)

标签: c++ multithreading boost


【解决方案1】:

看起来你想要一个信号量,所以你可以等待两个“资源”被“占用”。

现在,只需将互斥替换为原子。您仍然可以使用 cv 向服务员发出信号:

#include <boost/thread.hpp>

boost::mutex mut;       
boost::condition_variable cond;     

boost::atomic_bool data1_received(false);
boost::atomic_bool data2_received(false);

bool check_data_received()
{
    return (data1_received && data2_received);
}

void thread1()
{
    // Wait until socket data has arrived
    boost::unique_lock<boost::mutex> lock(mut);
    while (!cond.timed_wait(lock, boost::posix_time::milliseconds(200),
        boost::bind(&check_data_received)))
    {
        std::cout << "." << std::flush;
    }
}

void thread2()
{
    boost::this_thread::sleep_for(boost::chrono::milliseconds(rand() % 4000));
    data1_received = true;
    cond.notify_one();
}

void thread3()
{
    boost::this_thread::sleep_for(boost::chrono::milliseconds(rand() % 4000));
    data2_received = true;
    cond.notify_one();
}

int main()
{
    boost::thread_group g;
    g.create_thread(thread1);
    g.create_thread(thread2);
    g.create_thread(thread3);

    g.join_all();
}

注意:

  • 警告 - 您必须知道只有服务员在等待cv,否则您需要notify_all() 而不是notify_one()
  • 在工作人员发出完成信号之前等待服务员已经等待并不重要,因为谓词timed_wait 在阻塞之前会检查谓词。
  • 由于此示例使用原子和谓词等待,因此在互斥锁下发出cv 信号实际上并不重要。但是,线程检查器会(正确地)抱怨这一点(我认为),因为除非您添加锁定,否则它们不可能检查正确的同步。

【讨论】:

  • 感谢您的回答,但与我的原始代码有什么不同。您仍在使用谓词等待,但对于工作线程,您将 lock_guard 替换为 atomic_bool。这会带来哪些性能提升?
  • 没有锁定读/写共享状态(布尔值)。如果您期望连续加载,则在此处没有互斥锁的情况下“旋转”可能是有益的。然后你就实现了无锁同步。但是,无锁编程没有阻塞等待,所以如果没有连续工作,最终只会在旋转时烧毁 CPU。参见例如stackoverflow.com/questions/22486552/…
  • 如果您愿意,我可以稍后向您展示基于 thead_barrier 的解决方案。现在得走了
  • 好吧,只要你有时间,我会很高兴看到thread_barrier
  • 好的。这是旋转版本(实际上,如果没有thread1 中的睡眠,它会很有用,因为如果你需要它锁定不会有问题(请参阅我的答案解决方案),否则它将锁定 CPU 100%)coliru.stacked-crooked.com/a/119b35fea470acfe
猜你喜欢
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多