一.互斥量的介绍
1. 互斥量主要是用于线程间的同步,在多线程中主要是防止多个线程同时操作共享资源。
2.互斥的基本原则是,一旦某一个线程拥有互斥变量的所有权,操作共享的资源时,那么其他的线程就处于等待中,等待这个互斥量的所有权,一旦拥有所有权的线程释放互斥变量时,其他的线程才能取得互斥变量的所有权。
3.互斥量分为两种:独占式和共享式,互斥变量mutex的对象类大致如下:
(1).mutex,独占式互斥量,最简单的,而且是最常用的一种互斥变量。
(2).timed_mutex ,独占式互斥量,并提供超时锁定功能。
(3).recursive_mutex: 递归式互斥量,可以多次锁定,相应地也要多次解锁。
(4).recursive_timed_mutex: 它也是递归式互斥量,提供超时锁定功能。
(5).shared_mutex: multiple-reader/single-writer 型的共享互斥量(又称读写锁)。
二.下面来看个简单的例子:
#include <boost/thread.hpp>
#include <iostream>
using namespace std;
boost::mutex mutex; //定义一个锁
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
void thread()
{
for (int i = 0; i < 5; ++i)
{
wait(2);
mutex.lock(); //上锁
std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl; //多线程非安全的
mutex.unlock(); //释放锁
}
}
int main()
{
boost::thread t1(thread);
boost::thread t2(thread);
t1.join();
t2.join();
}
由于cout打印是线程非安全的,所以cout 打印在多线程中存在着资源的竞争性,多线程使用时需要加锁。另外,上锁操作完资源后,需要记得释放锁。程序运行的最后结果如下:
三.lock模板类使用
lock模板类也分为独占式的 和共享式的。lock模板类与mutex对象结合使用,在lock构造函数中调用互斥体mutex的lock方法,mutex对象 被锁住,一旦离开作用域,会自动调用lock的析构函数,释放锁。
(1).boost::unique_lock<T>,其中T可以mutex中的任意一种。(独占式),如:
boost::unique_lock<boost::mutex>,构造与析构时则分别自动调用lock和unlock方法,不需要手动的释放锁。
(2).boost::shared_lock<T>,其中的T只能是shared_mutex类。(共享锁)
四.下面以读写锁来举个例子
#include <boost/thread/locks.hpp>
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <iostream>
#include <functional>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
boost::shared_mutex mutex_;//共享锁
boost::mutex g_io_mutex;
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
class Counter
{
public:
Counter() : value_(0) {}
size_t Get() const
{
boost::shared_lock<boost::shared_mutex> lock(mutex_); //shared_lock 和share_mutex 配合使用
return value_;
}
void Put() //同一时间 只能有一个线程来访问
{
boost::unique_lock<boost::shared_mutex> lock(mutex_); //使用lock模板类
value_++;
}
private:
size_t value_;
};
void threadFunc(Counter& counter)
{
for (int i = 0; i < 3; ++i)
{
counter.Put(); //写入数据,锁住mutex
size_t value = counter.Get(); //多个线程可以同时读取数据
boost::lock_guard<boost::mutex> lock(g_io_mutex); //锁定 cout 打印输出,cout 是非线程安全的
std::cout << boost::this_thread::get_id() << ' ' << value << std::endl;
}
}
int main()
{
Counter counter;
boost::thread_group threads; //boost threads的线程组
for(int i =0;i< 3;i++)
{
threads.create_thread(boost::bind(threadFunc, boost::ref(counter)));//ref传入引用
}
threads.join_all();
return 0;
}
上例子中使用共享锁对象boost::shared_mutex,在写入数据时,mutex锁住 只能有一个线程可以写入数据,读取数据的时候,多个线程可以同时读取数据。在读取的时候,会阻塞所有企图写入数据的线程,知道所有的读取数据的线程访问结束,析构lock对象,释放锁时,才能获取到mutex的对象所有权。同理,在写入数据的时候,会阻塞任意一个企图写和企图读数据的线程。
程序的运行结果如下: