C ++中的带有while循环的条件变量

时间:2019-07-17 11:41:11

标签: c++ c++17

我试图弄清楚如何在C ++中使用std::condition_variable来实现“奇怪的”生产者和使用者程序,其中我对count变量设置了限制。

主线程(“生产者”)增加计数,必须等待该计数返回零以发出新的增量。

其他线程进入循环,在该循环中,它们必须减少计数器并发出通知。

之所以被封锁,是因为我不清楚如何通过在所有线程的函数内有序退出while循环来结束程序。

请问有人可以给我一些实施指导吗?

代码

#include <iostream>

#include <thread>
#include <condition_variable>
#include <vector>

int main() {
        int n_core = std::thread::hardware_concurrency();
    std::vector<std::thread> workers;
    int max = 100;
    int count = 0;
    std::condition_variable cv;
    std::mutex mutex;
    int timecalled = 0;


    for (int i = 0; i < n_core; i++) {
        workers.emplace_back(std::thread{[&max, &count, &mutex, &cv]() {
            while (true) {
                std::unique_lock<std::mutex> lk{mutex};
                std::cout << std::this_thread::get_id() << " cv" << std::endl;
                cv.wait(lk, [&count]() { return count == 1; });
                std::cout << std::this_thread::get_id() << " - " << count << std::endl;
                count--;
                std::cout << std::this_thread::get_id() << " notify dec" << std::endl;
                cv.notify_all();
            }
        }});
    }

    while (max > 0) {
        std::unique_lock<std::mutex> lk{mutex};
        std::cout << std::this_thread::get_id() << " cv" << std::endl;
        cv.wait(lk, [&count]() { return count == 0; });
        std::cout << std::this_thread::get_id() << " created token" << std::endl;
        count++;
        max--;
        timecalled++;
        std::cout << std::this_thread::get_id() << " notify inc" << std::endl;

        cv.notify_all();
    }

    for (auto &w : workers) {
        w.join();
    }

    std::cout << timecalled << std::endl; // must be equal to max
    std::cout << count << std::endl; // must be zero

}

问题

该程序没有结束,因为它停留在最后的join上。

预期结果

预期结果必须是:

100
0

所做的编辑

编辑1 :我在一段时间内将max > 0替换为true。现在循环是无限的,但是使用@ prog-fh的解决方案似乎可行。

编辑2 :我最后添加了一个变量来检查结果。

编辑3 :我将while(true)更改为while(max >0)。并发会不会是一个问题,因为我们正在读取它而没有锁?

2 个答案:

答案 0 :(得分:0)

线程正在等待cv.wait()调用中的新内容
但是,使用提供的lambda闭包可以观察到的唯一变化是count的值。
还必须检查max的值,以便有机会离开此cv.wait()调用。

代码中的最小更改可能是

cv.wait(lk, [&max, &count]() { return count == 1 || max<=0; });
if(max<=0) break;

假定对max的更改总是在互斥锁的控制下发生。


一项修改,以阐明对max的访问。

如果线程运行的循环现在为while(true),则仅在max同步的主体中读取mutex变量(感谢lk) 。
主程序运行的循环是while (max > 0):这里读取max时没有同步,但是唯一可以更改此变量的线程是主程序本身,因此从这个角度来看,它是纯串行代码。 /> mutex(由于lk)使此循环的整个内容同步,因此在这里更改max的值是安全的,因为线程中的读取操作在同一线程中同步方式。

答案 1 :(得分:0)

  1. 您遇到了竞争状况:在代码max中,多个线程可能会读取它们,而在main中对其进行了修改,这是根据C ++标准的竞争状况。

  2. 您在wait中使用的谓词似乎不正确(您正在使用==)。