2014-09-23 47 views
4

我可以訪問(不鎖定)一個std :: map條目,而另一個線程插入/擦除entrys?從另一個線程插入/擦除時,是否可以訪問C++ 11 std :: map條目?

例如僞C++:

typedef struct { 
    int value; 
    int stuff; 
}some_type_t; 

std::map<char,some_type_t*> my_map; 

//thread 1 does: 
my_map.at('a')->value = 1; 

//thread 2 does: 
some_type_t* stuff = my_map.at('b'); 

//thread 3 does: 
my_map.erase('c'); 

//I'm not modifying any elements T is a pointer to an previously allocated "some_type_t" 

STD C++ 11說,所有成員都應該是線程安全的(刪除()不是常量)。

回答

9

無無無無無!

map::erase使用map::at中使用的搜索算法修改映射條目和混淆之間的鏈接。您可以在擦除期間使用這些元素,但不能執行搜索算法本身!

我創建了一個圖形程序。在我的機器上,這個程序有時打印OK,有時會拋出一個地圖異常 - 這意味着搜索出錯了。增加閱讀線程的數量會使異常更頻繁地出現。

#include <iostream> 
#include <thread> 
#include <map> 
#include <cassert> 

std::map<int, int> m; 

// this thread uses map::at to access elements 
void foo() 
{ 
    for (int i = 0; i < 1000000; ++i) { 
    int lindex = 10000 + i % 1000; 
    int l = m.at(lindex); 
    assert(l == lindex); 
    int hindex = 90000 + i % 1000; 
    int h = m.at(hindex); 
    assert(h == hindex); 
    } 
    std::cout << "OK" << std::endl; 
} 

// this thread uses map::erase to delete elements 
void bar() 
{ 
    for (int i = 20000; i < 80000; ++i) { 
    m.erase(i); 
    } 
} 

int main() 
{ 
    for (int i = 0; i < 100000; ++i) { 
    m[i] = i; 
    } 

    std::thread read1(foo); 
    std::thread read2(foo); 
    std::thread erase(bar); 

    read1.join(); 
    read2.join(); 
    erase.join(); 

    return 0; 
} 
+0

+1表示答案是'否' – Soren 2014-09-25 06:47:32

-1

只要線程不同時訪問相同的地址不會有問題。

但對於直接回答你的問題,不,它不是,所以你不能沒有沒有任何錯誤鎖定去做線程安全的。

+1

您需要更清楚地明白「訪問同一地址」的含義 - 刪除或插入一個條目會影響地圖中鏈接的其他元素。 – Soren 2014-09-25 06:51:23

11

號是的。

兩個或多個線程可在地圖,其中一些非const操作也算執行const操作(即返回非const迭代運算,因此不是const,像begin和類似的東西)。

您還可以修改不讀/寫/刪除上述元素的非關鍵部件的運行(這是大多數人的mapset而其它操作元素的非關鍵部件,除了像erase東西或=)。

你不能eraseinsert或其它類似的非const地圖操作,同時與const和類似的地圖操作(如findat)做任何事情。請注意,如果添加元素,則[]可能類似於erase

該標準有非const操作即算作const線程安全的目的明確的名單 - 但他們基本上返回iterator&查找。

+0

非常好的解釋。 – Surt 2014-09-23 13:05:55

0

號的std ::地圖是不是線程安全的。英特爾的線程構建塊(tbb)庫有一些併發容器。檢查tbb

+0

這取決於您的線程安全定義,這不是一個明確定義的術語。例如,'std :: map'符合C++標準的線程安全要求,所以是「線程安全的」,但是這些要求不允許併發讀/寫單個對象,所以它也不是「線程安全的」安全」。除非你明確說明你是如何使用它,否則最好避免使用這個術語。 – 2016-01-28 13:41:36

相關問題