std::unique_lock与std::lock_guard

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

bool try_pop(T& value) { std::lock_guard 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_locklk(mtx); while (!ready) // 如果标志位不为 true, 则等待...cv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后,线程被唤醒, 继续往下执行} void put(){ std::unique_locklck(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 函数被调用时相同。
【std::unique_lock与std::lock_guard】在第二种情况下(即设置了 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封装类 };

    推荐阅读