根據https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57250,GCC 4.9支持原子shared_ptr
操作。GCC原子shared_ptr實現
使用GCC 4.9.2,我可以編譯使用原子shared_ptr
的程序。 -mcx16
標誌是必需的,因爲x86_64上的GCC實現顯然需要cmpxchg16b
,這很有意義,因爲我假設shared_ptr
上的原子操作需要原子上同時更新指針本身和引用計數。
但是,當我嘗試實際使用使用原子shared_ptr
庫時,它的行爲與我預期的不同。所以,要麼我沒有正確使用它,要麼GCC的實現是有缺陷的。大多數時候,我會99%相信我只是做錯了,但由於這是一個相對較新的功能,並且由於行爲看起來很奇怪,所以我只有50%的人相信這是我的錯案件。
下面是一個簡單的程序,創建一個原子shared_ptr
,然後執行一系列並行的讀取和對shared_ptr的寫道:
void test()
{
std::atomic<std::shared_ptr<int>> p(std::shared_ptr<int>(new int(10)));
std::cout << "Use count : " << p.load().use_count() << std::endl;
std::cout << "Initial value of p : " << *(p.load()) << std::endl;
std::vector<std::thread> threads;
const std::size_t num_threads = 8;
for (std::size_t i = 0; i != num_threads; ++i)
{
threads.emplace_back([&p, i](){
std::shared_ptr<int> x = p.load();
while (!p.compare_exchange_weak(
x,
std::shared_ptr<int>(new int(i + 5))
)) ;
});
}
for (auto& t : threads) t.join();
std::cout << "Use count : " << p.load().use_count() << std::endl;
std::cout << "Final value of p : " << *(p.load()) << std::endl;
}
當我編譯和運行,輸出爲:
~$ g++ test2.cpp -o test2 -std=c++11 -lpthread -mcx16
~$ ./test2
Use count : 1
Initial value of p : 0
Use count : 0
Final value of p : 0
但是這個輸出對我沒有意義。首先,在將原子shared_ptr
初始化爲值10
後,當我加載它並讀取初始值(在生成任何線程之前)時,我得到0
。其次,在所有線程加入後,即使沒有線程可能將其設置爲0
,值仍然爲0
。最奇怪的是,在線程加入之後,shared_ptr的use_count()
是0
!但原子shared_ptr
對象仍在範圍內,因此使用計數應爲1
。
我敢肯定的GCC實現這裏有缺陷的,但根據我上面貼的鏈接,GCC 4.9擁有一個完整的原子shared_ptr
實施,並...
~$ gcc --version
~$ gcc (Debian 4.9.2-10) 4.9.2
那麼...到底在這裏?我希望得到某種確認,要麼GCC 4.9.2的實現有缺陷或不完整,要麼我完全錯誤/困惑於如何使用原子shared_ptr
。
我不確定,但看起來也許是後者?在std :: atomic頁面的參考頁面上,它沒有提及shared_ptr的專門化:http://en.cppreference.com/w/cpp/atomic/atomic。事實上,當我嘗試編譯你的代碼時,我觸發了一個靜態斷言:error:static斷言失敗:std :: atomic需要一個可以複製的類型。所以看起來這是不正確的用法,並且在較舊的編譯器版本中代碼沒有被強化,導致一些奇怪的行爲。 –
這是一個針對* GCC 4.9的bug報告*,在5中修復。 –
您是否在任何可能的情況下將原子與鎖定混淆? – user2296177