2013-12-18 28 views
1

我目前正試圖圍繞使用C++ STL容器的線程安全問題來解決我的問題。我最近試圖通過使用std :: mutex作爲成員變量來實現一個線程安全的std :: vector,然後才意識到雖然我可以通過鎖定鎖使成員函數成爲線程安全的,但我無法使lib函數像std :: sort線程安全,因爲它們只能得到begin()/ end()迭代器,這是STL中容器和算法之間基本分離的結果。使用軟件事務存儲器的C++ std :: vector訪問

那麼我想,如果我不能使用鎖,軟件事務內存(STM)如何?

所以現在我堅持這一點:

#include <atomic> 
#include <cstdlib> 
#include <iostream> 
#include <thread> 
#include <vector> 

#define LIMIT 10 

std::atomic<bool> start{false}; 
std::vector<char> vec; 

void thread(char c) 
{ 
    while (!start) 
     std::this_thread::yield(); 

    for (int i = 0; i < LIMIT; ++i) { 
     __transaction_atomic { 
     vec.push_back(c); 
     } 
    } 
} 

int main() 
{ 
    std::thread t1(thread, '*'); 
    std::thread t2(thread, '@'); 

    start.store(true); 

    t1.join(); 
    t2.join(); 

    for (auto i = vec.begin(); i != vec.end(); ++i) 
     std::cout << *i; 

    std::cout << std::endl; 

    return EXIT_SUCCESS; 
} 

我與編譯:

g++ -std=c++11 -fgnu-tm -Wall 

使用G ++ 4.8.2,並且給了我以下錯誤:

error: unsafe function call to push_back within atomic transaction 

我有點得到,因爲push_back或排序或任何沒有聲明transaction_safe但離開我跟隨問題:

a)如何解決該錯誤?

b)如果我不能解決這個錯誤,那麼這些事務塊通常用於什麼?

c)如何實現一個無鎖線程安全向量?

在此先感謝!

編輯: 感謝迄今的答案,但他們並沒有真正抓我的癢。讓我舉個例子: 想象一下,我有一個全局向量,並且訪問這個向量應該在多個線程之間共享。所有線程都嘗試進行分類插入,因此它們會生成一個隨機數並嘗試以排序的方式將該數插入到矢量中,因此矢量始終保持排序(包括c的重複)。要執行排序的插入,他們使用std :: lower_bound來查找插入的「索引」,然後使用vector.insert()進行插入。

如果我爲包含std :: mutex作爲成員的std :: vector編寫一個包裝,比我可以編寫包裝函數插入使用std :: lock_guard鎖定互斥鎖,然後執行實際的std :: vector.insert()調用。但是std :: lower_bound並不會對成員互斥量產生任何影響。這是一個功能,而不是bug afaik。

這讓我的線程變得非常糟糕,因爲其他線程可以在某人正在做他的lower_bound事情時更改向量。

我能想到的唯一修復方法是:忘記包裝器,而不是全局互斥量。每當有人想對這個向量做任何事情時,他都需要這個鎖。

這樣的問題。使用這個全局互斥體有什麼替代方法。 和那裏軟件交易記憶浮現在腦海。

那麼現在:如何在STL容器上使用STM? (和a),b),c))。

+0

'std :: vector'已經是線程安全的。有關更多詳細信息,請參閱http://stackoverflow.com/questions/9042571/is-stdvector-or-boostvector-thread-safe。 – Nate

+0

Nah ..當我說「線程安全」時,這不是我的意思。我的意思是像真正的線程安全,而不是隻讀廢話。 – user2036087

回答

0

我不確定我明白你爲什麼不能使用互斥鎖。如果每次訪問該向量時都鎖定該互斥量,則無論您在做什麼操作,都可以確定一次只有一個線程正在使用它。根據您對安全載體的需求,確實有改進的空間,但互斥體應該是完全可行的。

鎖互斥 - >調用的std ::任何你需要排序或 - >解鎖互斥

如果對方你想要的是你的類使用std ::排序,那麼這又是一個問題通過你的容器的迭代器提供線程安全的訪問和讀取方法,因爲那些std :: sort需要用來排序一個向量的東西,因爲它不是容器的朋友或者任何類型的東西。

2

我相信你可以使STL容器100%線程安全的唯一方法是將它包裝在你自己的對象中(保持實際容器的私有性)並在你的對象中使用適當的鎖定(互斥鎖,無論),以便阻止多線程訪問STL容器。

這是在每個容器操作周圍鎖定調用程序中互斥量的道德等價物。

爲了使容器真正的線程安全,你必須仔細研究容器代碼,這是沒有規定的。

編輯:另外一個注意事項 - 小心你給你的包裝對象的接口。你不能很好地發佈對存儲對象的引用,因爲這可以讓調用者避開包裝器的鎖定。所以你不能僅僅通過互斥體複製矢量界面,並期望事情能夠發揮作用。

0

您可以使用簡單的互斥鎖來使您的類線程安全。正如另一個答案中所述,您需要在使用前使用互斥鎖來鎖定矢量,然後在使用後解鎖。

小心!所有的STL函數都會拋出異常。如果你使用簡單的互斥鎖,如果任何函數拋出因爲互斥體不會被釋放,你將會遇到問題。爲了避免這個問題,將互斥體包裝在一個將它釋放到析構函數中的類中。這是一個很好的編程習慣:http://c2.com/cgi/wiki?ResourceAcquisitionIsInitialization

相關問題