使用boost库实现线程的同步,下文主要讲解如何使用mutex,即互斥量来实现线程间的同步。
在使用boost库实现线程同步之前,我们先了解一下下面的概念:
对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程操作完毕,这其实就是线程的同步了。因此同步包括互斥,互斥其实是一种特殊的同步。
多线程同步互斥的四个实现方法——关键段、事件、互斥量、信号量。
临界资源和临界区
在一段时间内只允许一个线程访问的资源就称为临界资源或独占资源,计算机中大多数物理设备,进程中的共享变量等待都是临界资源,它们要求被互斥的访问。每个进程中访问临界资源的代码称为临界区。
boost锁的概述:
boost库中提供了mutex类与lock类,通过组合可以轻易的构建读写锁与互斥锁。
举个通俗的例子,如果共享资源是一个自动锁住的房间,互斥体是钥匙,进入房间必须取钥匙,离开房间应该还钥匙。这就对应着互斥体的lock(取钥匙)和unlock(还钥匙)。
1. Mutex对象
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
...
boost::try_mutex 等同于 boost::mutex, 用来兼容以前的版本。
boost::timed_mutex 支持超时的排他互斥对象。
boost::recursive_mutex 支持递归加锁的排他互斥对象。
的排他互斥对象。boost::recursive_timed_mutex 支持递归和超时
boost::shared_mutex
可共享的互斥对象。
2. Lock对象
#include <boost/thread/locks.hpp>
boost::lock_guard
是最简单的锁,构造时对传入的mutex加锁,析构时解锁。
boost::unique_lock
可以推迟lock(构造时指定defer_lock_t参数), 通过调用加锁函数显示lock: lock(), try_lock(), time_lock(), 可以调用unlock()解锁,或unique_lock对象析构时自动解锁。
boost::shared_lock
类似于unique_lock, 不同的是获得的是共享访问权限(前面获得的都是排他权限)。
boost::upgrade_lock
获得可升级的访问权限。
boost::upgrade_to_unique_lock
提升upgrade_lock权限,析构时upgrade_lock权限降级。
explicit upgrade_to_unique_lock(upgrade_lock<Lockable>& m_);
注意,Mutex和Lock是不同的东西,不要混淆了
mutex类主要讲解两种:boost::mutex,boost::shared_mutex,其中mutex有lock和unlock方法,shared_mutex除了提供lock和unlock方法外,还有shared_lock和shared_unlock方法。因此,boost::mutex为独占互斥类,boost::shared_mutex为共享互斥类。
lock模板类:
boost::unique_lock<T>,boost::shared_lock<T>,其中unique_lock为独占锁,shared_lock为共享锁。unique_lock<T>中的T可以为mutex类中的任意一种,如果为shared_mutex,那么boost::unique_lock<boost::shared_mutex>类的对象构造函数构造时,会自动调用shared_mutex的shared_lock方法,析构函数里,会自动调用shared_mutex的shared_unlock方法。如果是boost:: unique_lock<boost::mutex>,则分别自动调用lock和unlock方法。
boost::shared_lock<T>中的T只能是shared_mutex类。
读写锁的实现:
typedef boost::shared_lock<boost::shared_mutex> readLock;
typedef boost::unique_lock<boost::shared_mutex> writeLock;
boost::shared_mutex rwmutex;
void readOnly( )
{
readLock rdlock( rwmutex );
/// do something
}
void writeOnly( )
{
writeLock wtlock( rwmutex );
/// do something
}
对同一个rwmutex,线程可以同时有多个readLock,这些readLock会阻塞任意一个企图获得writeLock的线程,直到所有的readLock对象都析构。如果writeLock首先获得了rwmutex,那么它会阻塞任意一个企图在rwmutex上获得readLock或者writeLock的线程。boost::shared_lock使用要小心,千万不要同一个线程多次进入。
互斥锁的实现:
typedef boost::unique_lock<boost::mutex> exclusiveLock;
递归式的互斥量:
那么对于这种在一个线程中可能在锁中需要再次获得锁的情况,就需要使用重入锁,boost::recursive_mutex。防止死锁
void test4()
{
boost::recursive_mutex::scoped_lock<boost::recursive_mutex > lock(g_mutex);
boost::recursive_mutex::scoped_lock<boost::recursive_mutex > lock(g_mutex);
//do something...
}
scoped_lock:
scoped_lock是定义在namespace boost::detail::thread下的,为了方便我们使用(也为了方便设计者),mutex使用了下面的
typedef detail::thread::scoped_lock<mutex> scoped_lock;
这样我们就可以通过: boost::mutex::scoped_lock 来使用scoped_lock类模板了。
boost::mutex::scoped_lock
boost::mutexio_mutex;
void foo( )
{
{
boost::mutex::scoped_lock lock( io_mutex); /// 锁定
} /// 解锁
}