借shared_ptr实现copy-on-write

借助shared_ptr实现copy-on-write以提高多线程并发性能 锁竞争是服务器性能四大杀手之一(其他三个是:数据拷贝、环境切换、内存分配),本文将基于之前发布的kimgbo网络I/O库,以一个多线程群发聊天服务器的实现为例,介绍如何借助shared_ptr提高多线程并发的性能。 多线程群发聊天服务器实现的功能是,客户端连接服务器后,可以向服务器发送消息(消息=消息头+消息体),服务器负责将消息转发给其他正处于连接状态的客户端(包括发送消息的客户端)。示意图如 阅读详情
借shared_ptr实现copy-on-write

场景:
一个多线程的C++程序,24h x 5.5d运行。有几个工作线程ThreadW{0,1,2,3},处理客户发过来的交易请求,另外有一个背景线程ThreadB,不定期更新程序内部的参考数据。这些线程都跟一个hash表打交道,工作线程只读,背景线程读写,必然要用到一些同步机制,防止数据损坏。这里的示例代码用std::map代替hash表,意思是一样的:

typedef map<string, vector<pair<string, int> > > Map;

map 的 key 是用户名,value 是一个vector,里边存的是不同stock的最小交易间隔,vector已经排好序,可以用二分查找。

我们的系统要求工作线程的延迟尽可能小,可以容忍背景线程的延迟略大。一天之内,背景线程对数据更新的次数屈指可数,最多一小时一次,更新的数据来自于网络,所以对更新的及时性不敏感。Map的数据量也不大,大约一千多条数据。

最简单的同步办法,用读写锁,工作线程加读锁,背景线程加写锁。但是读写锁的开销比普通mutex要大,如果工作线程能用最普通的非重入Mutex实现同步,就不必用读写锁,性能较高。我们借助shared_ptr实现了这一点:

class Mutex;
class MutexLockGuard;

class CustomerData
{
 public:
  CustomerData() : data_(new Map)
  { }

  ~CustomerData();

  int query(const string& customer, const string& stock) const
  {
    MapPtr data = getData();
    // data 一旦拿到,就不再需要锁了。取数据的时候只有getData()内部有锁,多线程并发读的性能很好。

    // 假设用户肯定存在
    const EntryList& entries = (*data)[customer];
    return findEntry(entries, stock);
  }

  void update(const string& customer, const EntryList& entries );

 private:
  typedef vector<string, int> EntryList;
  typedef map<string, EntryList> Map;
  typedef tr1::shared_ptr<Map> MapPtr;

  static int findEntry(const EntryList& entries, const string& key) const
  { /* 用 lower_bound 在 entries 里找 key */ }

  MapPtr getData() const
  {
    MutexLockGuard lock(dataMutex_);
    return data_;
  }

  MapPtr data_;
  mutable Mutex dataMutex_;
};

关键看CustomerData::update()怎么写。既然要更新数据,那肯定得加锁,如果这时候其他线程正在读,那么不能在原来的数据上修改,得创建一个副本,在副本上修改,修改完了再替换。如果没有用户在读,那么就能直接修改,节约一次拷贝。

void CustomerData::update(const string& customer, const EntryList& entries )
{
  MutexLockGuard lock(dataMutex_);
  if (!data_.unique())
  {
    MapPtr newData(new Map(*data_));
    data_.swap(newData);
  }
  assert(data_.unique());
  (*data_)[customer] = entries;
}

注意其中用了shared_ptr::unique()来判断是不是有人在读,如果有人在读,那么我们不能直接修改,因为query()并没有全程加锁,只在getData()内部有锁。shared_ptr::swap()把data_替换为新副本,而且我们还在锁里,不会有别的线程来读,可以放心地更新。

据我们测试,大多数情况下更新都是在原来数据上进行的,拷贝的比例还不到1%,很高效。更准确的说,这不是copy-on-write,而是copy-on-other-reading。

我们将来可能会采用无锁数据结构,不过目前这个实现已经非常好,满足我们的要求。

用shared_ptr实现多线程对全局变量的读写,copy-on-write技术 参考陈硕的<>,中的用shared_ptr实现copy-on-write技术,不过这里的线程采用的是c++11的线程库 立即下载

相关推荐

稳定性仿真(stb闭环增益仿真)

stb仿真主要是测试电路的稳定性,例如运放在闭环电路中的增益和相位裕度的值,从而判别电路是否正常工作。 以下是stb仿真的过程: (1)调用iprobe器件 从analogLib中调iprobe器件,通过器件中的箭头标识确定接入电路的方法,箭头起点端连运放的输出端,箭头的终点端连在反馈环路的作用端。iprobe器件连入电路后相当于理想导线。(iprobe器件连接在反馈回路上) (2)analyses设置 勾选stb和frequency,此处的频率范围设置在0.1~1GHz,Probe Instance/T

qq_36686804的博客 3万+

使用shared_ptr实现copy-on-write

本文内容的核心思想不是博主的,本文是《Linux多线程服务端编程》中P52 "2.8借shared_ptr实现copy-on-write"的读后感。 感谢陈硕老师分享这么优秀的文章。欢迎大家阅读陈硕老师的原文,原文写的相当精彩。《Linux多线程服务端编程》https://book.douban.com/subject/20471211/ 多线程对临界区的访问 class Connection /*表示与客户端的连接句柄*/ { public: /*向客户端发送数据*/ void

专注音视频基础、WebRTC、ffmpeg、流媒体服务器 1129

思科模拟器实战:MQTT协议实现物联网设备通信全流程解析

本文详细解析了如何在思科模拟器中利用MQTT协议实现物联网设备通信的全流程。通过搭建网络拓扑、配置MQTT Broker与客户端,并编写发布/订阅逻辑,手把手指导读者完成一个“开关控制电灯”的经典物联网场景实验,帮助零成本掌握物联网通信核心。

weixin_29294975的博客 383

借shared_ptr实现copy-on-write (1)

在《Linux多线程服务端编程使用muduoC++网络库》2.8节说“借shared_ptr实现copy-on-write”。那么copy-on-write是怎样的技术?     COW(Copy-On-Write)通过浅拷贝(shallow copy)只复制引用而避免复制值;当的确需要进行写入操作时,首先进行值拷贝,再对拷贝后的值执行写入操作,这样减少了无谓的复制耗时。     特点如下:

q5707802的专栏 1076

海康威视 2DC 系列球机手机直连实用教程

海康威视2DC系列球机手机直连教程:首先确认设备支持直连功能并下载官方"海康互联"App;通过网线连接球机与路由器,使用SADP软件调整IP至同一网段;在App中添加设备并激活,完成调试即可远程查看监控画面。常见问题包括部分型号需远程解锁、网络连接异常等,可通过检查网络环境、联系客服等方式解决。本教程提供从准备到连接的完整指引,助您轻松实现手机监控管理。

海康威视技术支持 5416

免费获取船舶轨迹数据?手把手教你用Python处理中国海洋卫星AIS数据

本文详细介绍了如何免费获取中国海洋卫星AIS数据,并使用Python进行船舶轨迹数据的处理与分析。从数据源评估到自动化处理流水线,再到高级分析与可视化技巧,手把手教你避开常见问题,实现高效数据处理。特别适合航运数据分析、物流优化和海上安全研究等领域的研究者和开发者。

weixin_42616115的博客 321

C++之写时复制(CopyOnWrite)原理详解

CopyOnWrite允许多个对象共享相同的数据,避免了不必要的数据复制。这对于大型数据结构或多个对象需要引用相同数据的情况下,可以节省大量的内存。对于很少修改数据的情况下,CopyOnWrite可以显著提高性能。由于读操作不需要加锁,多个线程可以同时访问共享数据,提高并发访问的效率。对于一些读多写少的数据,写入时复制的做法就很不错,例如配置、黑名单、物流地址等变化非常少的数据,这是一种无锁的实现。可以帮我们实现程序更高的并发。减少数据拷贝。

红军不怕远征难,万水千山只等闲 2761

Tessent_StdcellLib

第二种为 Tessent Cell lib,既可用于功能仿真,也可以用于测试逻辑插入。lib包含了用于仿真的功能信息,也包含DFT cell属性。如何使用tessent工具将stdcell verilog 仿真模型转换为tessent自己的lib。运行后工具会生成一个atpg的lib文件,打开文件,找到一个带SI的DFF,只有功能描述。tessnt lib分为两种,第一种为ATBG lib,可以用于仿真;打开生成的lib文件,多了dft_cell_selection。第二部:编写attributes文件。

qq_40411444的博客 2135

shared_ptr:线程安全、循环引用

shared_ptr用来管理堆对象可以避免delete,但是注意shared_ptr本身是个对象因此其的声明周期、shared_ptr对象的读写操作非原子化那么在多线程环境下仍然存在很多问题,即shared_ptr对象本身的线程安全级别非100%。在多线程中访问同一个shared_ptr对象应该用mutex保护。    shared_ptr使用不当会延长锁管理的对象(假设为A)的生命周期,即有什

liuxuejiang158的专栏 3378

游戏安全逆向实战:如何用010Editor绕过ACE反作弊的文件校验(附详细步骤)

本文详细介绍了如何通过逆向工程思维和010Editor工具,针对PC游戏中ACE反作弊系统的文件校验机制进行分析与绕过。文章以实战案例为核心,逐步拆解了定位校验逻辑、解析校验数据文件、计算并替换哈希值的关键步骤,为安全研究人员提供了一种在用户态(Ring 3)层面进行轻量化对抗的思路与方法。

iii12的专栏 735

K-Core, K-Shell & K-Crust傻傻分不清楚

K-Core(K-核)就是所有大于等于K的K-Shell的并集;K-Crust(K-皮)就是所有小于等于K的K-shell的并集。

欢迎订阅 -- 小源笔迹 2256

【C++11智能指针】shared_ptr的初始化、拷贝构造和拷贝赋值、移动构造和移动赋值

1.智能指针概述 2.shared_ptr的初始化 2.1 shared_ptr和new结合使用(直接初始化) 2.2 make_shared函数 3.shared_ptr的拷贝构造和拷贝赋值 4.shared_ptr的移动构造和移动赋值 5.shared_ptr自动销毁所管理的对象 6.shared_ptr自动释放相关联的内存

脚踏实地,仰望星空 1万+

RK3588 部署 YOLOv5s 实战:多线程加速从 16FPS 飙升到 120FPS(含性能优化)

因为RK3588包含了3个NPU核心,支持3个核心同时工作、双核合作、以及单核工作。我们可以使用线程池来加速。线程池是一种长街的并发编程模型,它用于管理和复用线程,以提高多线程程序的性能和效率。线程池通常包含以下主要组件:1、任务队列:任务队列用于存储待执行的任务。这些任务可以是函数、方法或其他需要多线程环境中执行的操作。2、线程池管理:线程池管理器负责创建、销毁和管理线程。它会监视任务队列中的任务,根据需要创建线程,执行任务,并在任务完成后将线程放回池中以供重用。

FJN110的博客 100

理解 shared_ptr实现copy-on-write(COW)

shared_ptr实现COW(Copy-On-Write)

上善若水 2759

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

借shared_ptr实现copy-on-write(2)

转载自:http://blog.youkuaiyun.com/solstice/article/details/3351751 借shared_ptr实现copy-on-write 场景: 一个多线程的C++程序,24h x 5.5d运行。有几个工作线程ThreadW{0,1,2,3},处理客户发过来的交易请求,另外有一个背景线程ThreadB,不定期更新程序内部的参考数据。这些线程都跟一个

q5707802的专栏 326

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

shared_ptr实现copy-on-write

最近再看陈硕的《Linux多线程服务端编程使用muduoC++网络库》,2.8节看到这个内容:使用shared_ptr实现copy-on-write的手法降低锁竞争。 目的: 利用普通mutex替换读写锁 shared_ptr是引用技术型智能指针,当只有一个观察者时,引用计数为1。 对于write端,如果发现引用计数为1(即当前只有自己持有智能指针),那可以加锁后安全的修改。如果大于1,则需...

linux_Allen的博客 651

借 shared_ptr 实现 copy-on-write(避免死锁,mutex替换rwlock)

书中提到假设有下面代码: MutexLock mutex; std::vector<Foo> foos; void post(const Foo &f) { MutexLockGuard lock(mutex); foos.push_back(f); } void traverse() { MutexLockGuard lock(mutex); for(std::vector<Foo>::const_iterator it = foos.begin(); it !

Error Man 的博客 646

shared_ptr实现copy_on_write

参考:《linux多线程服务器编程---使用module网络库》(陈硕) 第二章 线程同步精要(P53-55)。 在多线程编程中,如果要用到修改共享资源的地方,如何正确地解决问题并提高效率? #include"mutex.h" #include<vector> #include<string> MutexLock mutex; classF...

weixin_30786617的博客 175

借shared_ptr实现copy on write 以减少锁的使用

shared_ptr是引用计数智能指针,如果当前只有一个观察者,那么引用计数为1,可以用shared_ptr::unique()来判断 对于write端,如果发现引用计数为1,这时可以安全地修改对象,不必担心有人在读它。 对于read端,在读之前把引用计数加1,读完之后减1,这样可以保证在读的期间其引用计数大于1,可以阻止并发写。 比较难的是,对于write端,如果发现引用计数大于1,该如何

le119126的专栏 650

shared_ptr实现多线程读写copy-on-write

利用boost的shared_ptr可以实现“读不阻塞写”。过程中每次读取不需要拷贝数据,而只需要在要写的时候拷贝一份数据: 点击(此处)折叠或打开 #include <iost...

cmbj68996的博客 365

muduo网络库:06---线程同步精要之(借shared_ptr实现copy-on-write)

本文内容衔接于前一篇文章(线程安全的Singleton实现):https://blog.youkuaiyun.com/qq_41453285/article/details/104875213

董哥的黑板报 1533
上一篇: 以boost::function和boost:bind取代虚函数
下一篇: 书摘几则
陈硕
博客等级 码龄26年 1万+粉丝 144原创
评论 37
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值