再看copy_on_write缩小临界区的例子
本例子是模拟的读者写者问题,采用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