1. 程式人生 > >boost::shared_ptr的執行緒安全

boost::shared_ptr的執行緒安全

官方文件的說明

shared_ptr objects offer the same level ofthread safety as built-in types. A shared_ptr instance can be "read"(accessed using only const operations) simultaneously by multiple threads.Different shared_ptr instances can be "written to" (accessed usingmutable operations such as operator= or reset) simultaneously by multiplethreads (even when these instances are copies, and share the same referencecount underneath.)

Any other simultaneous accesses result inundefined behavior.

shared_ptr物件提供同內建型別(int,double)一樣的執行緒安全性。一個shared_ptr例項能夠同時被多個執行緒“讀取”(通過const方法)。不同的shared_ptr例項可以同時被多個執行緒“寫入”,如==、reset等。(即使這些例項是同一個智慧指標的副本,它們都共享同一個引用計數物件)。

官方文件的例子

shared_ptr<int> p(new int(42));

//--- Example 1 ---

// thread A
shared_ptr<int> p2(p); // reads p

// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe
//同時讀取一個shared_ptr例項是執行緒安全的

//--- Example 2 ---

// thread A
p.reset(new int(1912)); // writes p

// thread B
p2.reset(); // OK, writes p2
//總結:不同的執行緒可以對兩個不同的shared_ptr例項進行寫入操作

//--- Example 3 ---

// thread A
p = p3; // reads p3, writes p

// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
//總結:同時對p3進行寫入和讀取操作不是執行緒安全的,行為是未定義的

//--- Example 4 ---

// thread A
p3 = p2; // reads p2, writes p3

// thread B
// p2 goes out of scope: undefined, the destructor is considered a "write access"
//總結:p2的析構算寫入操作,同時對p2進行讀取和寫入操作不是執行緒安全的,行為是未定義的

//--- Example 5 ---

// thread A
p3.reset(new int(1));

// thread B
p3.reset(new int(2)); // undefined, multiple writes
//總結:同時對p3進行寫入操作不是執行緒安全的,行為是未定義的

shared_ptr物件不能同時被讀取寫入的原因

因為 shared_ptr有兩個資料成員,讀寫操作不能原子化,使得多執行緒讀寫同一個 shared_ptr物件需要加鎖,否則會出現未知行為。

實際使用的建議

  1. 一個shared_ptr物件可以被多個執行緒同時讀取;

  2. 多個執行緒可以同時對多個shared_ptr例項進行寫入操作,即使這多個例項共有一個引用計數物件;

  3. 一個shared_ptr例項不能同時被多個執行緒寫入,也不能同時進行讀取和寫入操作。

  4. 如果多個執行緒要讀取寫入同一個shared_ptr例項,需要用鎖來保護該例項。

//這個例子來自於《Linux多執行緒服務端程式設計》 P18
MutexLock mutex;//鎖,用來保護全域性物件globalPtr
shared_ptr<Foo> globalPtr;

void doIt(const shared_ptr<Foo> & pFoo);

void read()
{
	shared_ptr<Foo> localPtr;
	{
		MutexLockGuard lock(mutex);
		localPtr = globalPtr;//讀globalPtr,寫localPtr
	}
	doIt(localPtr);//讀寫localPtr均無需再加鎖,localPtr不會同時被多個執行緒讀寫了
}

void write()
{
	shared_ptr<Foo> newPtr(new Foo);
	{
		MutexLockGuard lock(mutex);
		globalPtr = newPtr;//讀newPtr,寫globalPtr
	}
	doIt(newPtr);//讀寫newPtr均無需加鎖,newPtr不會同時被多個執行緒讀寫了
}