博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
shared_ptr实现copy_on_write
阅读量:5104 次
发布时间:2019-06-13

本文共 1929 字,大约阅读时间需要 6 分钟。

参考:《linux多线程服务器编程---使用module网络库》(陈硕)  第二章 线程同步精要(P53-55)。
    

在多线程编程中,如果要用到修改共享资源的地方,如何正确地解决问题并提高效率?

  1. #include"mutex.h"
  2. #include<vector>
  3. #include<string>
  4. MutexLock mutex;
  5. classFoo{
  6. public:
  7. void doit();
  8. };
  9. std::vector<Foo> foos;
  10. void post(constFoo&f){
  11. MutexLockGuard lock(&mutex);
  12. foos.push_back(f);
  13. }
  14. void traverse(){
  15. MutexLockGuard lock(&mutex);
  16. std::vector<Foo>::iterator iter=foos.begin();
  17. for(; iter!=foos.end(); iter++){
  18. iter->doit();
  19. }
  20. }
  21. voidFoo::doit(){
  22. Foo f;
  23. post(f);
  24. }
  25. int main(){
  26. Foo f;
  27. post(f);
  28. traverse();
  29. }
如上面的代码中,由于在traverse()中调用了doit()函数,而doit()中又调用了post,这两个函数里面都有锁存在,如何解决问题?

  1. #include"mutex.h"
  2. #include<vector>
  3. #include<string>
  4. #include<memory>
  5. MutexLock mutex;
  6. classFoo{
  7. public:
  8. void doit();
  9. };
  10. typedef std::vector<Foo>FooList;
  11. typedef std::shared_ptr<std::vector<Foo>>FooListPtr;
  12. FooListPtr g_foos(new std::vector<Foo>);
  13. void post(constFoo&f){
  14. MutexLockGuard lock(&mutex);
  15. if(!g_foos.unique()){
  16. g_foos.reset(newFooList(*g_foos));
  17. }
  18. g_foos->push_back(f);
  19. }
  20. void traverse(){
  21. FooListPtr local_foos;
  22. {
  23. MutexLockGuard lock(&mutex);
  24. local_foos =g_foos;
  25. }
  26. std::vector<Foo>::iterator iter=local_foos->begin();
  27. for(; iter!=local_foos->end(); iter++){
  28. iter->doit();
  29. }
  30. }
  31. voidFoo::doit(){
  32. Foo f;
  33. post(f);
  34. }
  35. int main(){
  36. Foo f;
  37. post(f);
  38. traverse();
  39. }
这里使用了copy_on_write办法来解决这个问题,就是写时拷贝的方法。
第一处:
    post()函数中,这里是往vector里面插入新的对象,这有可能破坏迭代器,引起在traverse的时候崩溃。于是它通过判读是否有
其它地方在引用该vector,也就是:
  1. if(!g_foos.unique())
如果有其它地方还在引用,那就把
g_foos重置指向新的地址,旧的地址就在被其它地方使用,当被使用完以后就自动释放,因为引用计数减0了,而且用了reset()。
后面就使用新的
new
FooList
(*
g_foos
)。
第二处:
    也就是在traverse中,
  1. MutexLockGuard lock(&mutex);
  2. local_foos =g_foos;
这里使用了一个临时的变量来引用g_foos,这样就可以使得原来被引用的计数加1。标志有其它地方在使用
g_foos。

使用写时拷贝的方法(copy_on_write),就解决了一些必须递归调用锁的问题。这种思想使用得比较广泛,如流表的管理就可以,首先将读写分离,将一个线程里面修改流表,转发线程都只读。

shared_ptr 的引用计数本身是安全且无锁的,但对象的读写则不是.
一个 shared_ptr 对象实体可被多个线程同时读取;
两个 shared_ptr 对象实体可以被两个线程同时写入,“析构”算写操作;
如果要从多个线程读写同一个 shared_ptr 对象,那么需要加锁。
 
 
 
 
 

转载于:https://www.cnblogs.com/yml435/p/6929888.html

你可能感兴趣的文章
【题解】[P4178 Tree]
查看>>
cer证书签名验证
查看>>
【深度学习】caffe 中的一些参数介绍
查看>>
QML学习笔记之一
查看>>
App右上角数字
查看>>
小算法
查看>>
WPF中实现多选ComboBox控件
查看>>
TestNG入门
查看>>
【ul开发攻略】HTML5/CSS3菜单代码 阴影+发光+圆角
查看>>
IO—》Properties类&序列化流与反序列化流
查看>>
Codeforces 719B Anatoly and Cockroaches
查看>>
ActiveMQ与spring整合
查看>>
格式化输出数字和时间
查看>>
关于TFS2010使用常见问题
查看>>
URL编码与解码
查看>>
剑指offer系列6:数值的整数次方
查看>>
poj2752 Seek the Name, Seek the Fame
查看>>
Illustrated C#学习笔记(一)
查看>>
理解oracle中连接和会话
查看>>
HDU 5510 Bazinga KMP
查看>>