C++读写锁shared_mutex实现
shared_mutex即读写锁,不同与我们常用的独占式锁mutex,shared_mutex是共享与独占共存的锁,实现了读写锁的机制,即多个读线程一个写线程,通常用于对于一个共享区域的读操作比较频繁,而写操作比较少的情况。
读写锁比起mutex具有更高的适用性,具有更高的并行性,可以有多个线程同时占用读模式的读写锁,但是只能有一个线程占用写模式的读写锁,读写锁的基本规则可以总结为“写优先,读共享,交叉互斥“,具体表现为读写锁的三种状态:
(1)当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。(交叉互斥)
(2)当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行加锁的线程将会被阻塞。(读共享,交叉互斥)
(3)当读写锁在读模式的锁状态时,如果有另外的线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁的请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求则长期阻塞。(写优先)
代码实现
#include <iostream>
#include <unistd.h>
#include <string>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/ref.hpp>
using namespace std;
using namespace boost;
在makefile中引入动态库文件 -lboost_system -lboost_thread
int g_num = 10; //全局变量,写者改变该全局变量,读者读该全局变量
boost::shared_mutex s_mu; //全局shared_mutex对象
//写线程
void read_(std::string &str)
{
const char* c = str.c_str();
while (1)
{
{
boost::shared_lock < boost::shared_mutex > lock(s_mu); //读锁定,shared_lock
printf("线程%s进入临界区,global_num = %d\n", c, g_num);
//boost::this_thread::sleep(boost::posix_time::seconds(1)); //sleep 1秒,给足够的时间看其他线程是否能进入临界区
printf("线程%s离开临界区...\n", c);
}
//boost::this_thread::sleep(boost::posix_time::seconds(1)); //读线程离开后再slpp 1秒(改变这个值可以看到不一样的效果)
}
}
//读线程
void writer_(std::string &str)
{
const char* c = str.c_str();
while (1)
{
{
boost::unique_lock < boost::shared_mutex > lock(s_mu); //写锁定,unique_lock
++g_num;
printf("线程%s进入临界区,global_num = %d\n", c, g_num);
usleep(1000*1000);//这里故意延时1秒钟,可以很直观的看到写锁定的时候,读锁是阻塞状态的
//boost::this_thread::sleep(boost::posix_time::seconds(1)); //sleep 1秒,让其他线程有时间进入临界区
printf("线程%s离开临界区...\n", c);
}
usleep(10*1000);
//boost::this_thread::sleep(boost::posix_time::seconds(2)); //写线程离开后再slpp 2秒,这里比读线程多一秒是因为如果这里也是1秒,那两个写线程一起请求锁时会让读线程饥饿
}
}
int main(int argc, char *argv[])
{
std::cout << "Hello world!" << std::endl;
std::string r1 = "read_1";
std::string r2 = "read_2";
std::string w1 = "writer_1";
std::string w2 = "writer_2";
boost::thread_group tg;
tg.create_thread(bind(read_, boost::ref(r1))); //两个读者
tg.create_thread(bind(read_, boost::ref(r2)));
tg.create_thread(bind(writer_, boost::ref(w1))); //两个写者
tg.create_thread(bind(writer_, boost::ref(w2)));
tg.join_all();
while (1);
return 0;
}