最近再看陈硕的《Linux多线程服务端编程使用muduoC++网络库》,2.8节看到这个内容:使用shared_ptr实现copy-on-write的手法降低锁竞争。
目的: 利用普通mutex替换读写锁
- shared_ptr是引用技术型智能指针,当只有一个观察者时,引用计数为1。
- 对于write端,如果发现引用计数为1(即当前只有自己持有智能指针),那可以加锁后安全的修改。如果大于1,则需要拷贝当前数据构再修改。代码实现就是拷贝构造一个新的FooList,然后在这个新的Foolist中写。
- 对于read端,在读之前加锁后将引用计数加1,就可以安全的读取。将引用计数加1,保证了写端不会去并发写。
void read()
{
FoolPtr foos; //智能指针对象
{
MutexLockGuard lock(mutex_);
foos = g_foos; //引用计数加1
}
for( .... )
//read ...
}
void write(const foo& f)
{
MutexLockGuard lock(mutex_);
if(!g_foos.unique()) //如果此时引用计数不为1,则需要拷贝对象
{
g_foos.reset(new FooList(*g_foos));
}
g_foos->push(f);
}
g_foos.reset 当g_foos仅仅只是将引用计数减1,只有当引用计数为1的时候,才会析构其管理的对象。
性能分析:
- read时:构造一个智能指针对象,引用计数加1,但是大大减小了锁的粒度
- write时:当发现引用计数大于1时,即有别的线程正在读,此时需要拷贝构造一个新的容器对象出来,然后在新的对象里write。当别的线程读取完毕时,随着智能指针对象析构,引用计数为0,原有容器对象也就析构了