在并发环境下锁的使用是家常便饭, 如何减少锁的使用是优化程序性能的一个方面. c++11里面新增了智能指针std::shared_ptr, 这个东西也许能给我们带来些启发. shared_ptr的一个特性是当引用计数为0时,它所拥有的堆内存会被自动释放. 利用这个特性我们可以做点实用的功能, 如下程序:

#include <assert.h>
#include <chrono>
#include <iostream>
#include <mutex>
#include <thread> std::shared_ptr<int> kNumPtr(new int(0));
std::mutex kmtx; std::shared_ptr<int> getSharedPtr()
{
kmtx.lock();
std::shared_ptr<int> ptr = kNumPtr;
kmtx.unlock();
return ptr;
} void dosomething(std::shared_ptr<int> ptr)
{
std::cout << "value: " << *ptr << std::endl;
} int main()
{ auto threadProc = [&](){
for(size_t i = 0; i < 100; ++i)
{
kmtx.lock();
if(!kNumPtr.unique()){
kNumPtr.reset(new int(*kNumPtr));
}
assert(kNumPtr.unique());
*kNumPtr = *kNumPtr + 1;
kmtx.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}; std::thread t1(threadProc);
std::thread t2(threadProc);
std::thread t3(
[&](){
for(size_t i = 0; i < 100000; ++i)
{
std::shared_ptr<int> ptr = getSharedPtr();
dosomething(ptr);
}
}
); t1.join();
t2.join();
t3.join(); std::cout << "kNumPtr's value: " << *kNumPtr << std::endl;
assert(*kNumPtr = 200);
assert(kNumPtr.unique());
}

  我们一共启动了三个线程, 这个程序模拟的场景是读的频率远远大于写的频率. 两个写线程模拟对共享数据的修改, 一个读线程用来模拟高频读的行为. dosomething模拟对数据的操作. 通常我们的程序需要在读操作的时候加上锁, 然而这里却只是加了一个锁用来做拷贝智能指针的操作,临界区的长度基本可以忽略, 如果dosomething的耗时很长, 比如服务器网络编程中通常的IO读写, 那么这个锁的开销其实是很大的, 对其它线程共享资源的访问性能延迟很大. 而如果换成现在的代码, 其代价几乎可以忽略.

  再看写线程, 其实写线程用了copy_on_write技术, 将旧有的共享资源拷贝到新的地址空间上, 比较重要的一点是这个旧有的资源其实在reset之后 其引用计数(use_count)的值其实为0, 如果在读线程中处理完毕之后, 操作系统会自动将这份旧有内存进行释放, 这点才是真正有意思的地方.

  程序地址:https://github.com/xiaopeifeng/CodeTricks/blob/master/shared_ptr_copyonwrite.cc

如何用shared_ptr减少锁的争用的更多相关文章

  1. The art of multipropcessor programming 读书笔记-3. 自旋锁与争用(2)

    本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...

  2. MYSQL线程池总结(一)

    线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应用服务还是DB服务,高并发请求始终是一个绕不开的话题.当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低 ...

  3. MyISAM 调度(优先级)的一些优化【转】

    MySQL的MyISAM引擎现在越来越被淡化了,但是还是有必要再温习总结一下的. 允许你改变语句调度的优先级,它可以使来自多个客户端的查询更好地协作,这样单个客户端就不会由于锁定而等待很长时间.改变优 ...

  4. MySQL查询优化--细节理论

    select的 high_priority还是比较有用,在实践中,平均5~6秒提高到3秒 ======================================================= ...

  5. mysql的mvcc(多版本并发控制)

    mysql的mvcc(多版本并发控制) 我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能. 什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列 ...

  6. 2015第15周日PostgreSQL学习

    英文版官网地址:http://www.postgresql.org/ 上面显示的最新版本信息是PostgreSQL 9.4.1, 9.3.6, 9.2.10, 9.1.15 & 9.0.19 ...

  7. Linux内存管理 (13)回收页面

    专题:Linux内存管理专题 关键词:LRU.活跃/不活跃-文件缓存/匿名页面.Refault Distance. 页面回收.或者回收页面也即page reclaim,依赖于LRU链表对页面进行分类: ...

  8. (转)MYSQL线程池总结(一)

    MYSQL线程池总结(一)  原文:http://www.cnblogs.com/cchust/p/4510039.html 线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应 ...

  9. Mysql 的InnoDB事务方面的 多版本并发控制如何实现 MVCC

    Mysql的MVCC不能解决幻读的问题,但是Mysql还有间隙锁功能,Mysql的间隙锁工作在Repeatable Read隔离级别下面,可以防止幻读, 参考:Mysql 间隙锁原理,以及Repeat ...

随机推荐

  1. MYSQL(二)

    上一篇文章讲的是mysql的基本操作,这一篇会有一点难以理解,本节主要内容mysql视图,存储过程,函数,事务,触发器,以及动态执行sql 视图view 视图是一个虚拟表,其内容由查询定义.同真实的表 ...

  2. C#高级编程笔记 Delegate 的粗浅理解 2016年9月 13日

    Delegate [重中之重] 委托 定义一:(参考)http://www.cnblogs.com/zhangchenliang/archive/2012/09/19/2694430.html 完全可 ...

  3. 下拉列表 select-option ; select-optgroup-option

    HTML中的下拉列表: <select> <option value ="1">Volvo</option> <option value  ...

  4. Oracle生成指定表的列名,并前后添加select from

    表的列名比较多的时候,手工一个个的写列名比较麻烦,这个函数可以让人偷偷懒 create or replace function f_GetCols(p_TableName in varchar2/*获 ...

  5. UVALive 4849 String Phone(2-sat、01染色)

    题目一眼看去以为是4-sat... 题意:给n(n<=3000)个黑方块的坐标,保证黑方块没有公共边.对于每个黑方块选一个角作为结点,使得所选结点满足输入的一个无向图.其中距离为曼哈顿距离.输出 ...

  6. [python面向对象]--基础篇

    1.#类 #类就是一个模板,模板里可以包含多个函数,函数里实现一些功能 #定义一个类 class bar: def foo(self,agr): print(self,agr) obj = bar() ...

  7. iOS开发 iOS10推送必看(基础篇)

    iOS10更新之后,推送也是做了一些小小的修改,下面我就给大家仔细说说.希望看完我的这篇文章,对大家有所帮助.   原文链接   一.简单入门篇---看完就可以简单适配完了相对简单的推送证书以及环境的 ...

  8. canvas画圆百分比显示

    代码如下,由于canvas还是不太熟悉,还有很多欠缺,希望大家多提意见,谢谢 function DrawArc(id,opations){ this.canvas = document.getElem ...

  9. sqlserver2000 数据库 'tempdb' 的日志已满

    方法一解决过程: 查看了下数据库的属性,是自动增长,不指定文件大小上限.在网上Google了很久,试了些方法都不行:数据库所在磁盘还有很大的可用空间,试着下重药了.直接把tempdb的数据文件和日志文 ...

  10. PHP的命名空间 与类是自动加载

    namespace 假设如果不使用namespace,那么每个类在一个项目中的名字就必须是固定的.因为php在new的时候不管是调用autoload还是调用已加载过的类,都存在一个类名对应的文件.所以 ...