本例子是模拟的读者写者问题,采用shared_ptr+写时拷贝实现,其中我觉得一个比较值得注意的地方是考虑到对象可能在临界区析构而将析构移除临界区,这对于多线程来说要多看多思。

#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<vector>
#include<assert.h>
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>
#include<boost/noncopyable.hpp>
using namespace std;
using namespace boost;
class Mutex:public noncopyable{//互斥量的封装
public:
Mutex(){
pthread_mutex_init(&mutex,NULL);
}
void lock(){
pthread_mutex_lock(&mutex);
}
void unlock(){
pthread_mutex_unlock(&mutex);
}
~Mutex(){
pthread_mutex_destroy(&mutex);
}
pthread_mutex_t* getMutex(){
return &mutex;
}
private:
mutable pthread_mutex_t mutex;
};
class MutexLockGuard:noncopyable{//RAII管理互斥量
public:
explicit MutexLockGuard(Mutex& mutex):mutex_(mutex){
mutex_.lock();
}
~MutexLockGuard(){
mutex_.unlock();
}
private:
Mutex& mutex_;//注意是引用,Mutex继承了noncopyable后不能拷贝构造
};
class test:noncopyable{
public:
test():ptr(new vector<int>),mutex(){}
void show(){
shared_ptr<vector<int> > temp=get();
for(vector<int>::iterator it=temp->begin();it!=temp->end();it++){
cout<<*it<<" ";
}
cout<<endl;
}
void add(int x){//添加一个元素
MutexLockGuard guard(mutex);
if(!ptr.unique()){
shared_ptr<vector<int> > temp(new vector<int>(*ptr));
ptr.swap(temp);
}
assert(ptr.unique());
ptr->push_back(x);
}
void add(vector<int> &x){//替换整个容器
shared_ptr<vector<int> > temp(new vector<int>(x));
if(temp){
MutexLockGuard guard(mutex);
ptr.swap(temp);//不使用ptr=temp的原因是旧的容器可能在此析构(没有读者,就只有一个写者在此处),那么临界区可能由于对象析构而变大,所以采用swap使可能的析构移除到临界区外....这个技术尤其重要...
}//此后可能析构对象
}
shared_ptr<vector<int> > get(){
return ptr;
}
private:
mutable Mutex mutex;
shared_ptr<vector<int> > ptr;//采用shared_ptr管理容器
};
shared_ptr<test> globalPtr(new test);
void* worker1(void* arg){
sleep(1);
globalPtr->show();
sleep(1);
globalPtr->show();
}
void* worker2(void* arg){
globalPtr->add(10);//添加一个元素
sleep(2);
vector<int> temp(1,100);
globalPtr->add(temp);//替换整个容器
}
int main(){
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,worker1,NULL);
pthread_create(&pid2,NULL,worker2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
return 0;
}

程序输出:

10 

100

再看copy_on_write缩小临界区的例子的更多相关文章

  1. mysql索引设计的注意事项(大量示例,收藏再看)

    mysql索引设计的注意事项(大量示例,收藏再看) 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过ke ...

  2. 再看Ajax

    再回顾Ajax相关的内容,再次梳理学习还是很有必要的,尤其是实际的开发中,ajax更是必不可少,仔细学习以便避免不必要的错误. 文章导读: --1.使用XMLHttpRequest---------- ...

  3. 再看ftp上传文件

    前言 去年在项目中用到ftp上传文件,用FtpWebRequest和FtpWebResponse封装一个帮助类,这个在网上能找到很多,前台使用Uploadify控件,然后在服务器上搭建Ftp服务器,在 ...

  4. 再看 AspriseOCR - OCR应用开发 -20151124

    再看 AspriseOCR - OCR应用开发 我写这个博文时间为 2015/11/24日,注意时间因为,网上很多文章时间上很久远,有的已经不能参考了 很多人面对从图片中识别文字或者数字0~9  A~ ...

  5. Android菜鸟的成长笔记(17)—— 再看Android中的Unbounded Service

    原文:Android菜鸟的成长笔记(17)-- 再看Android中的Unbounded Service 前面已经写过关于startService(Unbounded Service)的一篇文章:&l ...

  6. 再看case语句

    再看case语句,case语句只处理单条记录,而不是set 列名的使用,可以当做数值来使用: case when 后面简直是完美的的,什么东西都是能放的,只要是一个逻辑上的true/false的逻辑就 ...

  7. android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升

    android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升

  8. python基础----再看property、描述符(__get__,__set__,__delete__)

    一.再看property                                                                          一个静态属性property ...

  9. perf使用的问题,再看perf record,perf record 设置的采样频率,采样频率是如何体现在

    当perf stat -e branches 是统计 再看perf record,perf record是为了是记录时间发生的时候的调用栈, 在我的测试代码中总共有200,000,000条branch ...

随机推荐

  1. js文字转语音并播放

    这里调用的是百度文字转语音开放API html: <div> <input type="text" id="ttsText"> < ...

  2. KNN与SVM对比&SVM与逻辑回归的对比

    首先说一下两种学习方式: lazy learning  和  eager learning. 先说 eager learning, 这种学习方式是指在进行某种判断(例如,确定一个点的分类或者回归中确定 ...

  3. jQuery方法实现

    children 原生JavaScript中,如果希望找到某个元素的子元素,只能通过Node类型上的children方法一步一步获取.如 let li = document.querySelector ...

  4. STM32 System and Timer Clock Configurations

    STM32 System and Timer Clock Configurations I've started writing some software to drive a series of  ...

  5. [Go] sync.Once 的用法

    sync.Once.Do(f func()) 是一个非常有意思的东西,能保证 once 只执行一次,无论你是否更换 once.Do(xx) 这里的方法,这个 sync.Once块 只会执行一次. pa ...

  6. lodash用法系列(2),处理对象

    Lodash用来操作对象和集合,比Underscore拥有更多的功能和更好的性能. 官网:https://lodash.com/引用:<script src="//cdnjs.clou ...

  7. 通过进程ID获取基地址

    下面代码是通过进程ID来获取进程的基地址,创建一个进程快照后,读取进程模块,一般情况下第一个模块就是进程的基地址,下面的程序通过模块的字符串匹配来找到基地址.通过MODULEENTRY32来读取,下面 ...

  8. Delphi的自动编译软件Want

    Delphi自动编译环境的搭建及使用 什么是Want Want是一套Windows下用于编译Delphi源代码的工具.Want的名称是Windows Ant的意思. Ant是Java下最著名的自动编译 ...

  9. 利用mvn deploy命令上传包(转)

    本文转自https://blog.csdn.net/chenaini119/article/details/52764543 mvn安装 下载maven的bin,在apache官方网站可以下载. ht ...

  10. C#编程(二十九)----------泛型接口

    泛型接口 定义 先来看一个简单的例子: public class Sharp {} public class Rectangle:Sharp {} 上面定义了两个简单的类,一个是图形类,一个是矩形类; ...