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

目标是在 vector 中累积由生产者生成并由消费者插入 vector 的前十个自然整数。但是它不起作用,因为例如在某些运行中, vector 仅包含 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;
}

最佳答案

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

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

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

关于c++ - 条件变量基本示例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59154178/

10-12 14:12