为什么这段代码中的condition_variable会阻塞?

时间:2015-09-16 17:40:04

标签: c++ multithreading c++11 condition-variable

我是条件变量的新手,我想知道为什么这段代码在计数器变量后等于99? 删除for循环并将“counter + = 99”改为使代码有效,是否与sleep_for有关?感谢您的帮助:)

#include<thread>
#include<condition_variable>
#include<mutex>
#include<chrono>
#include <iostream>
std::condition_variable cv;
std::mutex mtx;
int counter = 0;

void foo() {
    std:: unique_lock<std::mutex>lck{ mtx };
    //counter += 99;
    for (; counter < 100; counter++) {
        std::cout << counter << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
    lck.unlock();
    cv.notify_one();
}

int main() {
    std::thread th(&foo);
    {
        std::unique_lock<std::mutex>lck{ mtx };
        cv.wait(lck, [] {
            return counter == 99;
        });
    }

    std::cout << "!!!!!" << std::endl;
    th.join();
}

2 个答案:

答案 0 :(得分:1)

让我们为您的代码添加一些注释:

void foo() {
    std:: unique_lock<std::mutex>lck{ mtx };
    // counter == 0
    for (; counter < 100; counter++) {
        ...
    }
    // counter == 100
    lck.unlock();
    cv.notify_one(); // <== notify here
}

我们循环到counter == 100,此时我们会通知cv。但是,我们正在等待counter == 99,这在获得通知时是不正确的。 wait()在代码中返回的唯一方法是在循环的最后一次迭代中发生虚假唤醒。

也许你打算在counter < 99时循环。

答案 1 :(得分:0)

(?!.*music$)

在循环结束时( B ),计数器的值为100.

#include<thread>
#include<condition_variable>
#include<mutex>
#include<chrono>
#include <iostream>
std::condition_variable cv;
std::mutex mtx;
int counter = 0;

void foo() {
    std:: unique_lock<std::mutex>lck{ mtx };
    //counter += 99;
    for (; counter < 100; counter++) {                                // B
        std::cout << counter << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
    }
    lck.unlock();
    cv.notify_one();                                                  // C
}

唤醒正在运行int main() { std::thread th(&foo); { std::unique_lock<std::mutex>lck{ mtx }; cv.wait(lck, [] { return counter == 99; // A }); } std::cout << "!!!!!" << std::endl; th.join(); } 的主题的条件是main()的值为99( A )。

因为您在完成循环后调用counter C ),unlock()的值为100.您的counter只会唤醒它std::condition_variable的值为99( A )时等待线程。因此,除非counter的值为99(这将导致counter的条件评估为std::condition_variable)时等待线程中存在虚假唤醒,否则您的等待线程将被困住等待永远。

您可以通过简单地更改true的谓词来解决此问题:

std::condition_variable

或(独家类型)通过更改 { std::unique_lock<std::mutex>lck{ mtx }; cv.wait(lck, [] { return counter == 100; // CHANGED TO 100 FROM 99. }); } 循环中的条件,如下所示:

for()