繁体   English   中英

c++ 中的 std::condition_variable::wait

[英]std::condition_variable::wait in c++

我对互斥锁、锁定和等待有点困惑。

这是我的代码:

void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {

    std::this_thread::sleep_for(std::chrono::seconds(1));

    m->lock();
    *signal = true;
    m->unlock();

    std::this_thread::sleep_for(std::chrono::seconds(3));

    cv->notify_one();

    printf("notify one\n");
    std::this_thread::sleep_for(std::chrono::seconds(10000));
}

void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {

    if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));
    std::unique_lock<std::mutex> lk(*m);

    cv->wait(lk, [&] { return (*signal); });

    printf("consumer %d passes this point!\n", index);
    std::this_thread::sleep_for(std::chrono::seconds(10000));
}

int main() {
    
    bool signal = false;
    std::mutex m;
    std::condition_variable cv;
    std::thread th1(producer, &m, &cv, &signal);
    std::thread th2(consumer, &m, &cv, &signal, 1);
    std::thread th3(consumer, &m, &cv, &signal, 2);

    th1.join();
    th2.join();
    th3.join();

    return 0;
}

添加了std::this_thread::sleep_for来解释我的问题。 有生产者、消费者1和消费者2。我认为这段代码应该如下工作:

  1. consumer1 遇到std::unique_lock<std::mutex> lk(*m); 所以它锁定。
  2. consumer1 遇到cv->wait 因为signal的初始值为false ,所以 consumer1 被阻塞并释放锁。
  3. 生产者遇到m->lock(); *signal = true; , m->unlock(); sleep_for 因此, signal变为true
  4. consumer2 遇到std::unique_lock<std::mutex> lk(*m); cv->wait(lk, [&] { return (*signal); }); . 因为signaltrue ,所以这个线程只是通过它。 所以, printf("consumer %d passes this point,\n"; index); 被执行。
  5. 生产者遇到cv->notify_one(); . 消费者 1 已解锁并检查情况。 因为signalture ,所以 consumer1 可以通过这一点。 因此, consumer1 满足printf

因此,我的预期结果是

consumer 2 passes this point!
notify one
consumer 1 passes this point!

然而,真正的结果是

consumer 2 passes this point!
notify one

好像consumer1不能通过cv->wait(lk, [&] { return (*signal); }); ,即使notify_one()被调用并且条件得到满足。 我的理解有什么问题吗?

您没有释放consumer程序中的锁定。 下面的代码符合预期:

#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>

void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {

    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::unique_lock<std::mutex> lk(*m);
        *signal = true;
    }
    std::this_thread::sleep_for(std::chrono::seconds(3));

    cv->notify_all();

    printf("notify one\n");
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {

    if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));

    {
        std::unique_lock<std::mutex> lk(*m);
        cv->wait(lk, [&] { return (*signal); });
    }

    printf("consumer %d passes this point!\n", index);
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

int main() {

    bool signal = false;
    std::mutex m;
    std::condition_variable cv;
    std::thread th1(producer, &m, &cv, &signal);
    std::thread th2(consumer, &m, &cv, &signal, 1);
    std::thread th3(consumer, &m, &cv, &signal, 2);

    th1.join();
    th2.join();
    th3.join();

    return 0;
}

注意std::unique_lock<std::mutex> lk(*m);周围的括号。 提供本地scope。

问题是消费者 2 在进入睡眠状态之前没有释放互斥锁上的锁:

std::unique_lock<std::mutex> lk(*m);

cv->wait(lk, [&] { return (*signal); });

printf("consumer %d passes this point!\n", index);   // <-- mutex is still locked here
std::this_thread::sleep_for(std::chrono::seconds(10000));

因此,即使消费者 1 中的条件可能满足,它也无法获取互斥锁上的锁,因为它已经被另一个线程锁定。

与对应的std::lock_guard相比, std::unique_lock为您提供了更细粒度的控制,包括解锁能力。 您可以做的是在消费者进入睡眠之前添加一个解锁调用,如下所示:

...
lk.unlock();
std::this_thread::sleep_for(std::chrono::seconds(10000));

否则,只有在消费者 2 执行完consumer() function 后,即长时间休眠后,才会释放互斥锁上的锁。

暂无
暂无

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

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