C++11std::unique_lock与std::lock_guard的区别及多线程应用实例编程
C++多线程编程中一般会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时形成资源争抢致使程序出现未定义的行为。一般的作法是在修改共享数据成员的时候进行加锁--mutex。在使用锁的时候一般是在对共享数据进行修改以前进行lock操做,在写完以后再进行unlock操做,进场会出现因为疏忽致使因为lock以后在离开共享成员操做区域时忘记unlock,致使死锁。安全
针对以上的问题,C++11中引入了std::unique_lock与std::lock_guard两种数据结构。经过对lock和unlock进行一次薄的封装,实现自动unlock的功能。数据结构
std::mutex mut; void insert_data() { std::lock_guard<std::mutex> lk(mut); queue.push_back(data); } void process_data() { std::unqiue_lock<std::mutex> lk(mut); queue.pop(); }
std::unique_lock 与std::lock_guard都能实现自动加锁与解锁功能,可是std::unique_lock要比std::lock_guard更灵活,可是更灵活的代价是占用空间相对更大一点且相对更慢一点。多线程
经过实现一个线程安全的队列来讲明二者之间的差异。函数
template <typename t=""> class ThreadSafeQueue{ public: void Insert(T value); void Popup(T &value); bool Empety(); private: mutable std::mutex mut_; std::queue<t> que_; std::condition_variable cond_; }; template <typename t=""> void ThreadSafeQueue::Insert(T value){ std::lock_guard<std::mutex> lk(mut_); que_.push_back(value); cond_.notify_one(); } template <typename t=""> void ThreadSafeQueue::Popup(T &value){ std::unique_lock<std::mutex> lk(mut_); cond_.wait(lk, [this]{return !que_.empety();}); value = que_.front(); que_.pop(); } template <typename t=""> bool ThreadSafeQueue::Empty() const{ std::lock_guard<std::mutex> lk(mut_); return que_.empty(); }
上面代码只实现了关键的几个函数,并使用了C++11新引入的condition_variable条件变量。从Popup与Inert两个函数看std::unique_lock相对std::lock_guard更灵活的地方在于在等待中的线程若是在等待期间须要解锁mutex,并在以后从新将其锁定。而std::lock_guard却不具有这样的功能。this
是C++11新引入的功能,lambda表达式,是一种匿名函数。方括号内表示捕获变量。当lambda表达式返回true时(即queue不为空),wait函数会锁定mutex。当lambda表达式返回false时,wait函数会解锁mutex同时会将当前线程置于阻塞或等待状态。线程
还存在另外一种读写锁,可是并无引入C++11,可是boost库提供了对应的实现。读写锁主要适合在于共享数据更新频率较低,可是读取共享数据频率较高的场合。code