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物件需要加鎖,否則會出現未知行為。
實際使用的建議
-
一個shared_ptr物件可以被多個執行緒同時讀取;
-
多個執行緒可以同時對多個shared_ptr例項進行寫入操作,即使這多個例項共有一個引用計數物件;
-
一個shared_ptr例項不能同時被多個執行緒寫入,也不能同時進行讀取和寫入操作。
-
如果多個執行緒要讀取寫入同一個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不會同時被多個執行緒讀寫了 }