對象構造要做到線程安全,唯一的要求是在構造期間不要洩漏this指針,即
1)不要在構造函數中注冊任何回調函數。
2)不要在構造函數中把this指針傳給跨線程的對象。
3)即便在構造函數的最後一行也不行。
之是以這樣是因為在構造函數執行期間對象還沒有完成初始化,通路這樣的對象會出現難以預料的結果。
對于析構函數,如果是單線程,隻需注意避免空懸指針(對象已經銷毀)和野指針(未初始化的指針)。而多線程時,就需要考慮很多因素了。一個動态建立的對象是否仍有效,光看指針是看不出來的。判斷一個指針是不是合法指針沒有高效的辦法,這是C/C++指針問題的根源。指向對象的原始指針是壞的,尤其當暴露給别的線程時,一個好的解決方法是使用引用計數型智能指針,即boost中的shared_ptr/weak_ptr。shared_ptr是強引用,控制對象的生命期;weak_ptr是若引用,不增加對象的引用次數,但是它知道對象是否還活着。如果對象還活着,那麼它可以提升為有效的share_ptr,如果對象已經死了,提升會失敗,傳回一個空的shared_ptr。shared_ptr是管理共享資源的利器,需要注意避免循環引用,通常的做法是ower持有執行child的shared_ptr,child持有指向owner的weak_ptr。下面以Observer模式為例。
Observable.h
#ifndef OBSERVABLE_H
#define OBSERVABLE_H
#include <boost/weak_ptr.hpp>
#include <vector>
#include <string>
using namespace std;
using namespace boost;
class Observer;
class Observable{
public:
Observable();
~Observable();
void registe(weak_ptr<Observer>);
void unregiste(weak_ptr<Observer>);
void notifyAll();
void setData(string,string);
private:
vector<weak_ptr<Observer> > observe;
string weather;
string humidity;
};
#endif
Observable.cpp
#include "Observable.h"
#include "Observer.h" //一定要包含,否則前項申明也不行
Observable::Observable(){
}
Observable::~Observable(){
}
void Observable::registe(weak_ptr<Observer> obs){
observe.push_back(obs);
}
void Observable::unregiste(weak_ptr<Observer> obs){
std::vector<weak_ptr<Observer> >::iterator it = observe.begin();
while(!(*(*it).lock() == *obs.lock())){
++it;
}
observe.erase(it);
}
void Observable::notifyAll(){
std::vector<weak_ptr<Observer> >::iterator it = observe.begin();
while(it != observe.end()){
shared_ptr<Observer> obj(it->lock());
if(obj){
obj->update(weather,humidity);
++it;
}
else
it = observe.erase(it);
}
}
void Observable::setData(string wea,string hum){
weather = wea;
humidity = hum;
notifyAll();
}
Observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
using namespace std;
using namespace boost;
class Observable;
class Observer:public enable_shared_from_this<Observer>{
public:
Observer(shared_ptr<Observable>);
void obser(shared_ptr<Observable>);
bool operator==(const Observer&);
~Observer();
void update(string,string);
private:
shared_ptr<Observable> subject;
};
#endif
Observer.cpp
#include "Observer.h"
#include "Observable.h"
#include <iostream>
using namespace std;
using namespace boost;
Observer::Observer(shared_ptr<Observable> sub):subject(sub){
}
void Observer::obser(shared_ptr<Observable> s){
(*s).registe(shared_from_this());
}
Observer::~Observer(){
}
bool Observer::operator==(const Observer& obs){
return *this == obs;
}
void Observer::update(string wea,string hum){
cout<<"Weather is "<<wea<<" and Humidity is "<<hum<<"\n";
}
testObser.cpp
#include "Observable.h"
#include "Observer.h"
int main(){
shared_ptr<Observable> subject(new Observable);
shared_ptr<Observer> p(new Observer(subject));
p->obser(subject);
subject->setData("Fine","Mid");
subject->setData("Bad","High");
return 0;
}
這裡需要注意shared_ptr循環引用的情況,此處使用weak_ptr來消除此隐患。