【问题标题】:use condition variable instead of lock_guard使用条件变量而不是 lock_guard
【发布时间】:2015-07-07 17:01:02
【问题描述】:

我有一个简单的程序,我想在其中输出数字 1-100,一个线程输出所有奇数,另一个线程输出所有偶数。使用 lock_guard,这是一项相当容易的任务。代码如下:

    #include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>

std::mutex m;


void print_numbers(int i)
{
    for (i; i <= 100; i++)
    {
        std::lock_guard<std::mutex> locker(m);
        std::cout << i << std::endl;
        ++i;
    }
}

int main()
{
    std::thread t1(print_numbers, 0);
    std::thread t2(print_numbers, 1);
    t1.join();
    t2.join();
    return 0;
}

我的问题是,我怎样才能使用条件变量来做到这一点,或者让它更优雅一点?

【问题讨论】:

  • 一个简单的std::mutex(和std::lock_guard)和一个std::condition_variable在某种程度上是正交概念。事实上,std::condition_variable 实际上需要使用至少 2 个互斥锁,所以如果这更优雅,则值得商榷。您使用条件变量来唤醒线程以进行状态更改,因此这些类似于信号量,我看不出您的代码实际上是如何需要的。
  • 我明白了,谢谢。不过,为了学习,您是否会提出一种使用两个带条件变量的互斥锁来实现相同结果的方法?
  • 好吧,您的代码示例甚至不需要 std::mutex,这两个线程完全独​​立于 i 的副本运行,更改永远不会干扰或容易发生对于比赛条件。你的std:mutex m; 是假的,不需要。
  • @πάνταῥεῖ:如何使用std:condition_variable 需要使用至少 2 个互斥锁?
  • 一般来说,当你有多个共享资源的消费者时,条件变量很有用,例如工人从队列中删除项目,并且有两个单独的考虑因素:资源是否可能处于消费者感兴趣的状态以及是否有人在考虑。您的互斥锁可以保护对std::cout 的访问,这绝对不是条件变量的用例。另一方面,您实现有序处理的愿望——虽然没有在示例中描述——可能会导致条件变量的用例,但可能会导致重新设计。

标签: c++ multithreading condition-variable


【解决方案1】:

您的代码中没有任何共享。每个线程都有一个局部变量 i。 POSIX 条件用于线程间通信/信令。这个想法很简单:

  1. 线程检查布尔谓词(取决于共享状态)并在谓词为假时决定“等待”(POSIX 中的 pthread_cond_wait)

  2. 另一个线程可以修改共享状态,因此会影响布尔谓词的值。如果这个线程改变了状态,它可以通知另一个线程(线程#1)它应该唤醒并重新检查其值现在可能已经改变的谓词(POSIX 中的 pthread_cond_signal 和 pthread_cond_broadcast)。

由于存在共享状态,您仍然需要一个互斥体来保护该共享状态并在您修改或访问它时“锁定”它。

POSIX 条件的典型用例是共享队列。消费者希望“消费”队列中的数据项,为此,必须等待布尔谓词[队列非空]。生产者生成它存放在共享队列中的数据项。当它添加项目时,它应该通知任何“服务员”他们应该重新检查。

底线:条件在这里没有帮助。在您的示例中,您甚至不需要互斥锁。并且条件必须与互斥锁一起使用(对 pthread_cond_wait 的调用将互斥锁的地址作为输入以原子地释放锁并在条件下休眠)。 mutex 用于互斥。条件适用于信令。两种截然不同的目的。

【讨论】:

  • 当然,如果我错了,请纠正我 Laurent Michel,@πάνταῥεῖ。我根本不在乎我。这里线程之间的共享资源是cout。如果我在这里不使用互斥锁,我会得到虚假输出,首先是所有偶数,然后是所有奇数。为了连续打印所有数字,我实际上需要一个互斥锁。
  • 您的代码表明您关心i,因为您在lock_guard 中增加了i。只在锁内做你绝对必须做的事情。
  • @lason:我的假设是 cout 用于调试。是的,打印必须同步,但这也是互斥的。这不会改变响应的性质:条件并不意味着解决互斥。它们旨在帮助发出信号。
猜你喜欢
  • 1970-01-01
  • 2016-11-29
  • 2018-01-20
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 2016-04-03
相关资源
最近更新 更多