用weak_ptr解决Observer模式的race condition*(能否用shared_ptr替代)

会发生race condition的简单observer模式

  • 典型场景(Observer模式):当Observable通知每一个Observer的时候,他从何得知Observer对象还活着?
    –如果在Observer的析构函数中调用unregister函数,会产生两个race condition
  1. 在调用unregister的时候如何得知通知者subject_是否还存活?
  2. 就算存活,线程A执行到unregister前,还没有来得及,而这时候线程B执行updata,指向的正好是A正在析构的对象。

问题出现了:x所指的observer正在被析构,这时任何调用非静态成员函数的动作都是不安全的。更糟的是observer是一个基类函数,执行到unregister的时候他的派生类对象已经被析构掉了,整个对象处于将死未死的状态。

class Observable;//先声明

class Observer//观察者
{
public:
	virtual ~Observer();//虚析构函数
	virtual void update()=0;//更新函数

	void observe(Observable *s);//绑定通知者
private:
	Observable * subject_;//通知者对象的指针
}

class Observable//通知者
{
public:
	void register_(Observer *x);//注册观察者
	void unregister(Observer *x);//注销观察者

	void notifyObservers()//轮询更新所有观察者
	{
		for(size_t i=0;i<Observers_.size();++i)
		{
			Observer *x=Obserbers_[i];
			if(x){
				x->update();
			}
		}
	}
private:
	std::vector<Observer*>Observer_;//绑定观察者的集合
}

Observer::~Observer()
{
	subject_->unregister(this);
}

void Observer::Observe(Observable *s)
{
	s->register_(this);
	subject_=s;
}

void Observable::register(Observer *x)
{
	Observers_.push_back(x);
}

void Observable::unregister(Observer *x)
{
	auto it=std::find(Observers_.begin(),Observers_.end(),x);
	if(it!=Observer_.end())
	{
		std::swap(*it,Observers.back());
		Observers.pop_back();
	}
}

通过weak_ptr解决Observer的race condition问题

通过weak_ptr能探查到对象的生死,那么Observer得到race condition就很容易解决,只要让Observable保存weak_ptr< observer >就可以了。
改进后的Observer代码如下所示:

#include<mutex>
#include<boost/enable_shared_from_this.hpp>
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>


class Observable;

class Observer:public boost::enable_shared_from_this<Observer>//观察者
{
public:
	virtual ~Observer();//析构函数为虚函数
	virtual void update() = 0;//update设置为纯虚函数,该类为纯虚类 

	void observe(Observable* s);//绑定通知者,在通知者中注册观察者
private:
	Observable* subject_;//绑定的通知者
};

class Observable//通知者
{
public:
	void register_(boost::weak_ptr<Observer> x);//注册观察者
	//不需要unregister,由于智能指针会在引用计数为0的时候自动析构对象,所以不需要unregister
	void notifyObservers()
	{
		std::lock_guard<std::mutex>guard(mutex_);//加互斥锁
		auto it = observers_.begin();
		while (it != observers_.end())//轮询
		{
			boost::shared_ptr<Observer> obj(it->lock());//将当前轮询到的weak_ptr提升为shared_ptr
			if (obj) {//成功就调用updata函数,b并且调到下一个
				obj->update();
				++it;
			}
			else {//失败说明当前对象已经被析构,输出信息并且移除vector
				std::cout << "notifyobservers() erase" << std::endl;
				it = observers_.erase(it);
			}
		}
	}

private:
	mutable std::mutex mutex_;
	std::vector<boost::weak_ptr<Observer>> observers_;
};

Observer::~Observer()
{
}

void Observer::observe(Observable* s)//在通知者中注册,并绑定通知者
{
	s->register_(shared_from_this());
	subject_ = s;
}

void Observable::register_(boost::weak_ptr<Observer> x)
{
	observers_.push_back(x);
}

class Foo :public Observer
{
	virtual void update()
	{
		std::cout << "Foo::update()" << this << std::endl;
	}
};

int main()
{
	Observable subject;
	{
		boost::shared_ptr<Foo> p(new Foo);
		p->observe(&subject);
		subject.notifyObservers();
	}
	subject.notifyObservers();
	return 0;
}

在这里插入图片描述
可以看到,在出p的作用域之前use_count是1,那么当出作用域之后这个对象Foo就会被析构。

用shared_ptr替代weak_ptr会怎么样呢?

改成shared_ptr后除非手动调用unregister()否则observer对象永远不会被析构。

#include<vector>
#include<iostream>
#include<algorithm>
#include<mutex>
#include<boost/enable_shared_from_this.hpp>
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>


class Observable;

class Observer:public boost::enable_shared_from_this<Observer>//观察者
{
public:
	virtual ~Observer();//析构函数为虚函数
	virtual void update() = 0;//update设置为纯虚函数 

	void observe(Observable* s);
private:
	Observable* subject_;//绑定的通知者
};

class Observable//通知者
{
public:
	void register_(boost::shared_ptr<Observer> x);
	//不需要unregister
	void notifyObservers()
	{
		std::lock_guard<std::mutex>guard(mutex_);
		auto it = observers_.begin();
		while (it != observers_.end())
		{
			boost::shared_ptr<Observer> obj(*it);
			if (obj) {
				obj->update();
				++it;
			}
			else {
				std::cout << "notifyobservers() erase" << std::endl;
				it = observers_.erase(it);
			}
		}
	}

private:
	mutable std::mutex mutex_;
	std::vector<boost::shared_ptr<Observer>> observers_;
};

Observer::~Observer()
{
}

void Observer::observe(Observable* s)//在通知者中注册,并绑定通知者
{
	s->register_(shared_from_this());
	subject_ = s;
}

void Observable::register_(boost::shared_ptr<Observer> x)
{
	observers_.push_back(x);
}

class Foo :public Observer
{
	virtual void update()
	{
		std::cout << "Foo::update()" << this << std::endl;
	}
};

int main()
{
	Observable subject;
	{
		boost::shared_ptr<Foo> p(new Foo);
		p->observe(&subject);
		subject.notifyObservers();
	}
	subject.notifyObservers();
	return 0;
}

在这里插入图片描述
在程序运行到末尾的时候可以看到:该对象并没有被析构,引用指针计数仍然为1,程序不结束的话就永远存在。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值