首页 > 解决方案 > c++ 中的 std::condition_variable::wait

问题描述

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

这是我的代码:

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. 消费者 1 满足cv->wait。因为初始值为signalis false,所以 consumer1 被阻塞,锁被释放。
  3. 生产者遇到m->lock();, *signal = true;,m->unlock();sleep_for. 因此,signal变为true
  4. 消费者 2 满足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 已解锁并检查情况。因为signalis ture,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()被调用并且条件得到满足。我的理解有什么问题吗?

标签: c++multithreading

解决方案


您没有在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);以提供本地范围。


推荐阅读