简体   繁体   English

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

[英]Condition Variable with a while loop in thread in C++

I'm trying to figure out how to use std::condition_variable in C++ implementing a "strange" producer and consumer program in which I had set a limit to the count variable. 我试图弄清楚如何在C ++中使用std::condition_variable来实现“奇怪的”生产者和使用者程序,在该程序中我对count变量设置了限制。

The main thread ("producer") increments the count and must wait for this to return to zero to issue a new increment. 主线程(“生产者”)递增计数,并且必须等待该计数返回零以发出新的递增值。

The other threads enters in a loop where they have to decrease the counter and issue the notification. 其他线程进入一个循环,在其中它们必须减少计数器并发出通知。

I am blocked because it is not clear to me how to conclude the program by orderly exiting the while loop inside the function of all threads. 我之所以受阻,是因为我不清楚如何通过在所有线程的函数内有序退出while循环来结束程序。

Could someone give me some guidance on how to implement it, please? 有人可以给我一些实施指导吗?

Code

#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

}

Problem 问题

The program doesn't end because it is stuck on some final join . 该程序没有结束,因为它停留在某些最终join

Expected Result 预期结果

The expected result must be: 预期结果必须是:

100
0

Edits Made 编辑完成

EDIT 1 : I replaced max > 0 in the while with a true . 编辑1:我更换了max > 0的同时用true Now the loops are unbounded, but using the solution of @prog-fh seems to work. 现在循环是无限的,但是使用@ prog-fh的解决方案似乎可行。

EDIT 2 : I added a variable to check the result in the end. 编辑2 :我添加了一个变量来最后检查结果。

EDIT 3 : I changed while(true) to while(max >0) . 编辑3 :我将while(true)更改为while(max >0) Could this be a problem in concurrency because we are reading it without a lock? 难道这是并发性的问题,因为我们没有锁阅读它?

The threads are waiting for something new in the call cv.wait() . 该线程正在等待呼叫新的东西 cv.wait()
But the only change that can be observed with the provided lambda-closure is the value of count . 但是提供的lambda闭包唯一可以观察到的变化是count的值。
The value of max must be checked too in order to have a chance to leave this cv.wait() call. 还必须检查max的值,以便有机会离开此cv.wait()调用。

A minimal change in your code could be 您的代码中的最小变化可能是

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

assuming that changes to max always occur under the control of the mutex. 假设max更改始终在互斥锁的控制下发生。


An edit to clarify around the accesses to max . 修改以澄清对max的访问。

If the loop run by the threads is now while(true) , then the max variable is only read in its body which is synchronised by mutex (thanks to lk ). 如果线程运行的循环现在为while(true) ,则max变量仅在其主体中读取,该主体由mutex体同步(感谢lk )。
The loop run by the main program is while (max > 0) : max is read without synchronisation here but the only thread that can change this variable is the main program itself, so it's pure serial code from this perspective. 主程序运行的循环是while (max > 0) :这里读取max没有同步,但是唯一可以更改此变量的线程是主程序本身,因此从这个角度来看,它是纯串行代码。
The whole body of this loop is synchronised by mutex (thanks to lk ) so it is safe to change the value of max here since the read operations in the threads are synchronised in the same way. 此循环的整个过程由mutex (由于lk )同步,因此可以安全地在此处更改max的值,因为线程中的读取操作以相同的方式同步。

  1. You're having race conditions: in your code max may be read by multiple threads, whilst it is being modified in main , which is a race condition according to C++ standard. 您遇到了竞争状况:在代码中max可能被多个线程读取,而在main对其进行了修改,这是根据C ++标准的竞争状况。

  2. The predicates you are using in wait seems to be incorrect (you're using == ). 您在wait中使用的谓词似乎不正确(您正在使用== )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM