來(lái)看一下boost文檔下給出的shared_ptr的多線程讀寫的例子
shared_ptr<int> p(new int(42));
//一個(gè)shared_ptr實(shí)體允許被多個(gè)線程讀取
// thread A
shared_ptr<int> p2(p); // reads p
// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe
//一個(gè)shared_ptr實(shí)體不允許被多個(gè)線程同時(shí)讀寫
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
shared_ptr引用計(jì)數(shù)是原子的,它的析構(gòu)函數(shù)原子地將引用計(jì)數(shù)減去1,當(dāng)多個(gè)線程對(duì)同一對(duì)象析構(gòu)時(shí),也只會(huì)出現(xiàn)執(zhí)行順序的交錯(cuò),不會(huì)有內(nèi)存泄露。
那么同理shared_ptr的構(gòu)造函數(shù)、賦值、析構(gòu)都是線程安全的。
何時(shí)不安全呢?就是在我們通過shared_ptr.get()和*解引用獲得了指向該內(nèi)存的原始指針,那么后面都是對(duì)原始指針的操作,所以我們需要自己控制線程的安全。(如shared_ptr.rest 和 swap)
通俗來(lái)講,當(dāng)我們同時(shí)讀寫同一個(gè)對(duì)象的時(shí)候,無(wú)法確保編譯器是先操作引用計(jì)數(shù)還是先操作指針,在這個(gè)時(shí)候就需要加鎖,避免出現(xiàn)空懸指針。
那么如何使多個(gè)線程可以對(duì)同一個(gè)shared_ptr實(shí)體進(jìn)行同時(shí)讀寫?
運(yùn)用weak_ptr這個(gè)助手檢測(cè)指針是否被釋放
沒使用前:
class tester
{
public:
tester() {}
~tester() {}
public:
boost::shared_ptr<int> m_spData; // 可能其它類型。
};
tester gObject;
void fun(void)
{
// !!!在這大量使用sp指針.
boost::shared_ptr<int> tmp = gObject.m_spData;
}
int main()
{
// 多線程。
boost::thread t1(&fun);
boost::thread t2(&fun);
t1.join();
t2.join();
return 0;
}
改進(jìn)后:
class tester
{
public:
tester() {}
~tester() {}
// 更多的函數(shù)定義…
};
void fun(boost::weak_ptr<tester> wp)
{
boost::shared_ptr<tester> sp = wp.lock;
if (sp)
{
// 在這里可以安全的使用sp指針.
}
else
{
std::cout << “指針已被釋放!” << std::endl;
}
}
int main()
{
boost::shared_ptr<tester> sp1(new tester);
boost.weak_ptr<tester> wp(sp1);
// 開啟兩個(gè)線程,并將智能指針傳入使用。
boost::thread t1(boost::bind(&fun, wp));
boost::thread t2(boost::bind(&fun, wp));
t1.join();
t2.join();
return 0;
}
使用weak_ptr.lock函數(shù)就可以得到一個(gè)shared_ptr的指針,如果該指針已經(jīng)被其它地方釋放,它則返回一個(gè)空的shared_ptr,也可以使用weak_ptr.expired()來(lái)判斷一個(gè)指針是否被釋放。