条件变量condition_variable用法学习

转自:https://www.cnblogs.com/fenghualong/p/13855360.html

1.介绍

 condition_variable类似于信号量机制,实现了线程的等待和唤醒。

  • wait() :阻塞等待的同时释放锁(原子操作),还可以添加阻塞判断函数,详见代码
  • notify_all() : 唤醒所有阻塞等待的线程
  • notify_one(): 唤醒某一个等待的线程

2.例子

锁+条件变量 实现等待唤醒。

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

std::mutex mylock;
std::condition_variable condVar;

bool dataReady{false};

void waitingForWork() {
    std::cout << "Waiting ..." << std::endl;
    std::unique_lock<std::mutex> l(mylock);  // 加了unique_lock锁
    condVar.wait(l, []{return dataReady;});           // (4)
    std::cout << "Running ..." << std::endl;
}

void setDataReady() {
    {
        std::lock_guard<std::mutex> l{mylock};  // 加了lock_guard锁
        dataReady = true;
    }
    std::cout << "Data prepared, notify one" << std::endl;
    condVar.notify_one();                             // (3)
}

int main(int argc, char const *argv[])
{
    std::cout << "==========Begin==========" << std::endl;

    std::thread t1(waitingForWork);                    // (1)
    std::thread t2(setDataReady);                      // (2)

    t1.join();
    t2.join();

    std::cout << "===========End===========" << std::endl;
    cout<<endl;
    return 0;
}
// 运行结果
-> % ./main
==========Begin==========
Waiting ...
Data prepared, notify one
Running ...
===========End===========

如果不用锁和等待条件控制,可能会导致虚假唤醒和唤醒丢失问题。

2.1 wait函数原理

转自chatgpt

template<typename Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred) {
    while (!pred()) {// 判断条件,条件返回false
        pthread_mutex_unlock(lock.mutex()->native_handle()); // 解锁unique_lock
        pthread_cond_wait(&cv, lock.mutex()->native_handle());// 等待唤醒
        pthread_mutex_lock(lock.mutex()->native_handle()); // 加锁
    }
}
  1. 外部锁定互斥量: 当调用 wait 函数时,互斥量已经被 std::unique_lock 锁定。std::unique_lock 提供了对互斥量的独占访问。
  2. 解锁互斥量并等待: wait 函数会临时解锁互斥量,然后使当前线程进入阻塞状态,等待条件变量的通知。这一步骤是原子操作,确保在解锁和进入等待状态之间没有竞态条件。内部实现可能会调用互斥量的 unlock 方法和操作系统提供的等待机制。
  3. 被唤醒后重新锁定互斥量: 当条件变量被通知(通过 notify_one 或 notify_all),被阻塞的线程会被唤醒。在被唤醒后,wait 函数会重新锁定互斥量。 
  4. 检查条件并继续执行: 唤醒后,线程会检查条件是否满足。如果条件仍然不满足,线程会再次进入等待状态。否则,wait 函数返回,线程继续执行后续的代码。

3.用条件变量实现信号量

https://blog.csdn.net/qq_24447809/article/details/115906017

#pragma once
#include<mutex>
#include<condition_variable>
class semaphore {
public:
    semaphore(long count = 0) :count(count) {}
    void wait() {
        std::unique_lock<std::mutex>lock(mx);
        cond.wait(lock, [&]() {return count > 0; });
        --count;
    }
    void signal() {
        std::unique_lock<std::mutex>lock(mx);
        ++count;
        cond.notify_one();
    }

private:
    std::mutex mx;
    std::condition_variable cond;
    long count;
};

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
condition_variable是C++11中的一个同步原语,常和mutex搭配使用,用于阻塞一个线程或同时阻止多个线程,直到另一个线程修改共享变量并通知condition_variable。它可以防止多线程场景下,共享变量混乱。理解条件变量需要先理解三个概念:锁、wait等待和notify通知。 condition_variable的使用方法如下: 1.定义condition_variable对象和mutex对象 ```c++ std::condition_variable cv; std::mutex cv_m; ``` 2.资源修改线程步骤 ```c++ std::unique_lock<std::mutex> lk(cv_m); // 修改共享变量 cv.notify_one(); // 通知等待的线程 ``` 3.资源等待线程步骤 ```c++ std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk, []{return true/false;}); // 等待条件变量 ``` 其中,wait函数会自动释放锁,等待条件变量被通知后重新获取锁。 4.代码示例 4.1 无需notify场景 ```c++ #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void print_id(int id) { std::unique_lock<std::mutex> lck(mtx); while (!ready) cv.wait(lck); std::cout << "thread " << id << '\n'; } void go() { std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all(); } int main() { std::thread threads[10]; for (int i = 0; i < 10; ++i) threads[i] = std::thread(print_id, i); std::cout << "10 threads ready to race...\n"; go(); for (auto& th : threads) th.join(); return 0; } ``` 4.2 正常应用场景1 ```c++ #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool data_ready = false; void consumer() { std::unique_lock<std::mutex> lck(mtx); cv.wait(lck, []{return data_ready;}); std::cout << "Consumer: data is ready\n"; } void producer() { std::unique_lock<std::mutex> lck(mtx); data_ready = true; cv.notify_one(); } int main() { std::thread t1(consumer); std::thread t2(producer); t1.join(); t2.join(); return 0; } ``` 4.3 正常应用场景2 ```c++ #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool data_ready = false; void consumer() { std::unique_lock<std::mutex> lck(mtx); cv.wait(lck, []{return data_ready;}); std::cout << "Consumer: data is ready\n"; data_ready = false; } void producer() { std::unique_lock<std::mutex> lck(mtx); data_ready = true; cv.notify_one(); } int main() { std::thread t1(consumer); std::thread t2(producer); t1.join(); t2.join(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值