首页 > 解决方案 > 条件变量基本示例

问题描述

我正在学习 C++11 中的条件变量,并根据示例代码编写了这个程序。

目标是将生产者生成并由消费者推入向量的前十个自然整数累积到向量中。但是它不起作用,因为例如在某些运行中,向量仅包含 1、7 和 10。

#include <mutex>
#include <condition_variable>
#include<vector>
#include <iostream>
#include <cstdio>

std::mutex mut;
#define MAX     10
int counter;
bool isIncremented = false;
std::vector<int> vec;
std::condition_variable condvar;

void producer() {
    while (counter < MAX) {
        std::lock_guard<std::mutex> lg(mut);
        ++counter;
        isIncremented = true;
        condvar.notify_one();
    }
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> ul(mut);
        condvar.wait(ul, [] { return isIncremented; });
        vec.push_back(counter);
        isIncremented = false;
        if (counter >= MAX) {
            break;
        }
    }
}

int main(int argc, char *argv[]) {
    std::thread t1(consumer);
    std::thread t2(producer);
    t2.join();
    t1.join();

    for (auto i : vec) {
        std::cout << i << ", ";
    }
    std::cout << std::endl;
    // Expected output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
    // Example of actual output: 1, 7, 10,

    std::cout << "Press enter to quit";
    getchar();
    return 0;
}

标签: c++condition-variable

解决方案


问题是你只记得你的生产者生产的最后一个数字。你的生产者永远不会等到消费者消费完它生产的东西。如果您的生产者线程在消费者线程开始运行之前对其循环进行了多次迭代(这并非不可能,因为循环没有做太多),消费者将只会看到生产者产生的最后一个数字并且只会推送那个进入向量...</p>

为了解决这个问题,要么使用第二个条件变量让生产者等待某人获取它产生的最后一个结果,要么使用可以在生产者和消费者之间存储多个结果的东西,或者两者的组合......</p >

注意:通知条件变量不是阻塞调用。如果是这样,它必须要求您交出互斥锁,以便它可以在内部释放它,否则您最终会陷入死锁。notify_one()只会唤醒正在等待条件变量的线程之一并返回。被唤醒线程阻塞的等待调用将在它返回之前重新获取互斥锁。在您的情况下,消费者线程不太可能被唤醒,然后无法重新获取互斥锁并立即再次阻塞,因为您的生产者线程在调用时仍然持有互斥锁notify_one()。因此,作为一般经验法则,如果您在调用 notify 之前持有与条件变量关联的互斥锁,您希望释放它……</p>


推荐阅读