美文网首页
条件变量

条件变量

作者: _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;
    };
    

    相关文章

      网友评论

          本文标题:条件变量

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