美文网首页
std::unique_lock与std::lock_guard

std::unique_lock与std::lock_guard

作者: 宋大壮 | 来源:发表于2019-03-14 16:16 被阅读0次

    std::lock_guard

    std::lock_guard是RAII模板类的简单实现,功能简单。

    bool try_pop(T& value)
        {
            std::lock_guard<std::mutex> lk(mut);
            if(data_queue.empty())
            {
                return false;
            }
            return True;      //析构时自动解锁
        }
    

    std::unique_lock

    std::unique_lock为锁管理模板类,是对通用mutex的封装。std::unique_lock对象以独占所有权的方式(unique owership)管理mutex对象的上锁和解锁操作,即在unique_lock对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而unique_lock的生命周期结束之后,它所管理的锁对象会被解锁。unique_lock具有lock_guard的所有功能,而且更为灵活。虽然二者的对象都不能复制,但是unique_lock可以移动(movable),因此用unique_lock管理互斥对象,可以作为函数的返回值,也可以放到STL的容器中。

    std::condition_variable 对象通常使用 std::unique_lock 来等待,如果需要使用另外的 lockable 类型,可以使用std::condition_variable_any类.

    void get(int id)
    {
        std::unique_lock <std::mutex> lk(mtx);
    
        while (!ready) // 如果标志位不为 true, 则等待...
    
            cv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后,线程被唤醒, 继续往下执行
    
    }
    void put()
    
    {
        std::unique_lock <std::mutex> lck(mtx);
    
        ready = true; // 设置全局标志位为 true.
    
        cv.notify_one(); // 唤醒一个线程.
    }
    

    关于notify()和notifyAll()

    notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
    void notify(): 唤醒一个正在等待该对象的线程。
    void notifyAll(): 唤醒所有正在等待该对象的线程。
    两者的最大区别在于:
    notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
    notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。

    std::condition_variable.wait

    std::condition_variable提供了两种 wait() 函数。当前线程调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。

    在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程唤醒了当前线程),wait()函数也是自动调用 lck.lock(),使得lck的状态和 wait 函数被调用时相同。

    在第二种情况下(即设置了 Predicate),只有当 pred 条件为false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。因此第二种情况类似以下代码:

    data_cond.wait(lk, [this]{
                return !data_queue.empty();
            })
    

    自制RAII锁

    class MutexLock{
     public:
        explicit MutexLock(Mutex* mu):_mutex(mu){ lock(_mutex) } //构造时自动上锁 explicit:显示调用构造函数
        ~MutexLock(){ unlock(_mutex) }
    
     private:
        Mutex* _mutex;  //Mutex 为mutex封装类
    };
    

    相关文章

      网友评论

          本文标题:std::unique_lock与std::lock_guard

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