美文网首页
条件变量

条件变量

作者: _gentle | 来源:发表于2018-07-17 22:25 被阅读0次

条件遍历是一种同步机制,它阻塞线程直到满足某个条件,避免忙等待。C++11提供了两种条件变量,需要添加头文件#include<condition_variable>

  • condition_variable:配合std::unique_lock<std::mutex>进行wait操作
  • condition_variable_any: 和任意带有lock、unlock语义的mutex搭配使用,比较灵活,但效率比condition_variable差一些
  • 可以用condition_variable_any实现一个同步队列,它是一个简单的生产者/消费者模型的实现,缺点是会产生饥饿。
#include<iostream>
#include<thread>
#include<mutex> 
#include<chrono>
#include<condition_variable>
#include<list> 
template<typename T>
class SyncQueue {
public:
    bool empty() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.empty();
    }
    bool full() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size == m_maxSize();
    }
    SyncQueue(int maxSize):m_maxSize(maxSize){
    
    }
    
    void put(const T& x) {
        std::lock_guard<std::mutex> locker(m_mutex);
    //  while(isFull()){
//          std::cout << "the buffer is full" << std::endl;
//          m_notFull.wait(m_mutex); //等待临界区未满的条件 
//      }
        m_notFull.wait(m_mutex, [this]{return !isFull();});
        m_queue.push_back(x);
        m_notEmpty.notify_one();
    } 
    void Take(T& x) {
        std::lock_guard<std::mutex> locker(m_mutex);
    //  while(isEmpty()) {
        //  std::cout << "the buffer is empty" << std::endl; 
    //      m_notEmpty(m_mutex);//等待临界区非空的条件 
    //  }
        m_notEmpty.wait(m_mutex, [this]{return !isEmpty();}); //这种写法与上面的等价,但更简洁 
        x = m_queue.front();
        m_queue.pop_front();
        m_notFull.notify_one();// 唤醒一个在等待临界区未满的线程 
    }
    size_t Size() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size(); 
    }
    int Count() {
        return m_queue.size();
    }
private:
    bool isFull() const {//这是一个非同步方法 
        return m_queue.size() == m_maxSize;
    }
    
    bool isEmpty() const {//这是一个非同步方法 
        return m_queue.empty();
    }
    std::list<T> m_queue;
    std::mutex m_mutex;
    std::condition_variable_any m_notEmpty;
    std::condition_variable_any m_notFull;
    int m_maxSize;
};

上面代码中wait会释放mutex,而lock_guard此时还拥有mutex,出现了语义不一致。如果此时线程结束,lock_guard析构会导致错误。

下面用condition_variable 和 unique_lock来实现同步队列。unique_lock可以随时释放锁(lock_guard析构的时候才会释放),因此wait函数中释放锁不会导致语义不一致

#include<iostream>
#include<thread>
#include<mutex> 
#include<chrono>
#include<condition_variable>
#include<list> 
template<typename T>
class SyncQueue {
public:
    bool empty() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.empty();
    }
    bool full() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size == m_maxSize();
    }
    SyncQueue(int maxSize):m_maxSize(maxSize){
    
    }
    
    void put(const T& x) {
        std::unique_lock<std::mutex> locker(m_mutex);
        m_notFull.wait(m_mutex, [this]{return !isFull();});
        m_queue.push_back(x);
        m_notEmpty.notify_one();
    } 
    void Take(T& x) {
        std::unique_lock<std::mutex> locker(m_mutex);
        m_notEmpty.wait(m_mutex, [this]{return !isEmpty();}); //这种写法与上面的等价,但更简洁 
        x = m_queue.front();
        m_queue.pop_front();
        m_notFull.notify_one();// 唤醒一个在等待临界区未满的线程 
    }
    size_t Size() {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size(); 
    }
    int Count() {
        return m_queue.size();
    }
private:
    bool isFull() const {//这是一个非同步方法 
        return m_queue.size() == m_maxSize;
    }
    
    bool isEmpty() const {//这是一个非同步方法 
        return m_queue.empty();
    }
    std::list<T> m_queue;
    std::mutex m_mutex;
    std::condition_variable m_notEmpty;
    std::condition_variable m_notFull;
    int m_maxSize;
};

相关文章

  • 条件变量

    条件变量: 条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。为什么有...

  • 条件变量

    条件遍历是一种同步机制,它阻塞线程直到满足某个条件,避免忙等待。C++11提供了两种条件变量,需要添加头文件#in...

  • 条件变量

    多线程中代替轮询 考虑一种情形:有一个容器,里面时任务,只要容器不为空,那么就有很多个线程去处理里面的任务。同时有...

  • 条件变量

    头文件:#include 与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁!条件变量用来自动阻...

  • pthread_cond_t条件变量

    Linux下C编程的条件变量: 条件变量是线程中的东西,就是等待某一条件的发生,和信号一样。 用法 条件变量使我们...

  • JS 变量 条件

    变量 声明变量同时赋值 var name='亚索';var number=20; 先声明变量再赋值 var nam...

  • Go条件变量

    条件变量:本身不是锁,但是经常和锁结合使用。对应有3个常用方法。wait,signal,broadcast1、fu...

  • 6.2、业务逻辑之打通业务处理脉搏实战

    1、多线程互斥量+条件变量线锁住互斥量,取队列,到条件变量等待的三个步骤。调用条件变量的时候释放互斥量,使得其他线...

  • Axure RP 8 条件编辑器

    Axure RP8 条件编辑器之条件 值:文本/数字的值或变量; 变量值:储存在变量中的...

  • kotlin - 学习笔记

    变量 条件 循环 异常 null 空安全 类 接口 类扩展方法 with 变量 条件 循环 异常 null 空安全...

网友评论

      本文标题:条件变量

      本文链接:https://www.haomeiwen.com/subject/mjvgpftx.html