会发生race condition的简单observer模式
- 典型场景(Observer模式):当Observable通知每一个Observer的时候,他从何得知Observer对象还活着?
–如果在Observer的析构函数中调用unregister函数,会产生两个race condition
- 在调用unregister的时候如何得知通知者subject_是否还存活?
- 就算存活,线程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,程序不结束的话就永远存在。