2012-07-14 395 views
19

是unique_ptr線程安全嗎?下面的代碼不可能兩次打印相同的數字嗎?是unique_ptr線程安全嗎?

#include <memory> 
#include <string> 
#include <thread> 
#include <cstdio> 

using namespace std; 

int main() 
{ 
    unique_ptr<int> work; 

    thread t1([&] { 
     while (true) { 
      const unique_ptr<int> localWork = move(work); 
      if (localWork) 
       printf("thread1: %d\n", *localWork); 
      this_thread::yield(); 
     } 
    }); 

    thread t2([&] { 
     while (true) { 
      const unique_ptr<int> localWork = move(work); 
      if (localWork) 
       printf("thread2: %d\n", *localWork); 
      this_thread::yield(); 
     } 
    }); 

    for (int i = 0; ; i++) { 
     work.reset(new int(i)); 

     while (work) 
      this_thread::yield(); 
    } 

    return 0; 
} 

回答

16

不,它不是線程安全被讀取。

這兩個線程都可能是move工作指針沒有明確的同步,所以兩個線程都可能得到相同的值,或者兩者都可能得到一些無效的指針......這是未定義的行爲。

如果你想要做這樣的事情正確,你可能需要使用像這樣std::atomic_exchange兩個線程可以讀取/修改共享工作指針與正確的語義。

+0

「令人興奮的是,當如果發生這種情況,它也將導致整的雙重釋放。」它可能*。它可能不會。它可能導致根本不釋放該整數。它可能會導致兩個移動的版本都有指針值的一半。它可以做各種事情。 – 2012-07-14 17:29:23

+0

的確,我對這個架構做了一些假設,而這些架構並沒有真正的保證。 – Useless 2012-07-14 19:05:26

7

根據Msdn

以下線程安全規則適用於標準 C++庫中的所有類(除shared_ptr的和iostream類,如下所述 )。

單個對象是線程安全從多個線程讀取。例如,對於給定對象A的 示例,可以同時從線程2讀取線程1的A和線程 以安全。

如果單個對象正在被一個線程寫入,則全部讀取到 並寫入該對象上的相同或其他線程必須被 保護。例如,給定對象A,如果線程1正在寫入 A,則線程2必須被阻止讀取或寫入A.

即使讀取和寫入類型的一個實例也是安全的另一個 線程正在讀取或寫入相同類型的不同實例。 例如,給定對象A和相同類型的B,它是安全的,如果A 正被寫入線程1和B在螺紋2.

28

的unique_ptr是線程安全的正確使用。你破壞了不成文的規則:你不應該通過引用在線程之間傳遞unique_ptr。

背後的unique_ptr的理念是,它在任何時候都一個單一的(唯一的)的所有者。因此,您可以始終在線程之間安全地傳遞它,而無需同步 - 但您必須通過值來傳遞它,而不是通過引用來傳遞它。一旦您創建別名到unique_ptr,您將失去唯一性屬性,並且所有投注都將關閉。不幸的是,C++不能保證唯一性,所以你留下了一個你必須遵循的約定。不要爲unique_ptr創建別名!

+0

有趣的觀察。我試着去思考什麼時候通過引用來傳遞unique_ptr是有意義的。我的意思是當你不想通過所有權的情況下。 – Ghita 2012-07-14 18:51:16

+0

如果'在線程之間傳遞'意味着使用unique_ptr參數啓動一個新線程,那麼您可以將unique_ptr替換爲幾乎任何類型,並仍然將其稱爲線程安全。任何東西是正確使用線程安全:) – 2012-08-04 15:43:32

+1

你確定嗎?我的內心偏執的程序員告訴我,如果你在線程之間傳遞它是UB,因爲你不確保seq_cst,也就是說,如果最後指向的是由線程1修改,然後向上傳遞給線程2,那麼線程2可能會看到過時的值指向東西。 – NoSenseEtAl 2012-12-31 08:48:40

相關問題