互斥量、锁和条件变量

1 lock_guard<mutex> lock

1.1 直接操作mutex的lock/unlock函数

多线程访问同一资源时,为了保证数据的一致性,必要时需要加锁mutex,表示任一时刻,只能有一个线程访问该对象,加锁mutex

#include <iostream>
#include <boost>
 
std::mutex m_buf;
 
void Counter(){
   m_buf.lock();
   int i=++count;// 只有当一个线程输出完毕了,另一个线程才能输出
   m_buf.unlock();
}

int main(){
  boost::thread_group threads;// 创建进程
  for(int i=0;i<4;i++)
      threads.create_thread(&Counter);
  threads.join_all();
 return 0;
}

1.2 使用 lock_guard/unique_lock 自动加锁、解锁

类似智能指针,与 1.1 相比只需要加锁,后面无须解锁 unlock()


#include <iostream>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
 
boost::mutex mutex;
int count = 0;
 
void Counter() {
  // lock_guard 在构造函数里加锁,在析构函数里解锁。
  boost::lock_guard<boost::mutex> lck(mutex);
 
  int i = ++count;
  std::cout << "count == " << i << std::endl;
}
 
int main() {
  boost::thread_group threads;
  for (int i = 0; i < 4; ++i) {
    threads.create_thread(&Counter);
  }
 
  threads.join_all();
  return 0;
}

unique_lock<mutex> lck(m); 就是创建了一个unique_lock对象lck,并将其与互斥量mutex绑定,同时对其上锁。

1.3 unique_lock 和 lock_guard 区别

  1. unique_lock不需要始终拥有关联的mutex,而lock_guard始终拥有mutex。这意味着unique_lock需要利用owns_lock()判断是否拥有mutex。
  2. unique_lock可以进行临时解锁和再上锁,如在构造对象之后使用lck.unlock()就可以进行解锁,lck.lock()进行上锁,而不必等到析构时自动解锁。
  3. unique_lock还接受第二个参数来进行构造。unique_lock lck(m,perd):仅仅是将lck与m绑定,不会自动进行lock()和unlock(),需要配合条件变量使用。

如果要结合使用条件变量 condition_variable,应该使用 unique_lock

2 条件变量 condition_variable

条件变量主要包括两个函数 wait() 和 notify_one/all()

void wait(unique_lock<mutex>& _Lck)
{	// wait for signal
    _Cnd_waitX(_Mycnd(), _Lck.mutex()->_Mymtx());
}
 
template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{	// wait for signal and test predicate
    while (!_Pred())
        wait(_Lck);
}

函数有两个参数,程序执行到 wait() 语句时:

  1. 对互斥量加锁。
  2. 执行第二个参数表示的函数 _Pred。
  3. 函数 _Pred 返回 false 时,对互斥量解锁,程序阻塞,等待其它线程调用 nofify_one() 将其唤醒后,回到步骤(1)。
  4. 函数 _Pred返回 true 时,程序继续执行。

函数只有一个参数,程序执行到 wait() 语句时阻塞(相当于第二参数表示的函数始终返回false),等待其它线程调用 nofify_one() 将其唤醒后,再继续执行(相当于第二参数表示的函数始终返回true)。