当另一个线程插入/删除entrys时,我可以访问(不锁定)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说所有成员都应该是线程安全的(erase()不是const)。
答案 0 :(得分:11)
没有。是的。
两个或多个线程可以在地图上执行const
操作,其中一些非const
操作也会计数(返回非const
迭代器的操作,因此不是{{ 1}},像const
和类似的东西一样。)
您还可以修改begin
或map
元素的非关键组件,同时修改其他不读/写/销毁所述元素的非关键组件的操作(除了set
或erase
之类的内容之外,其中大多数都是这样的。
使用=
和类似地图操作(例如erase
或insert
执行任何操作时,您无法const
或find
或其他类似的非常规地图操作)。请注意,如果添加了元素,at
可能与[]
类似。
标准有一个明确的非erase
操作列表,为了线程安全,它们被计为const
- 但它们基本上是返回const
或{{1}的查找}}
答案 1 :(得分: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;
}
答案 2 :(得分:0)
没有。 std :: map不是线程安全的。英特尔的线程构建块(tbb)库有一些并发容器。查看tbb
答案 3 :(得分:-1)
只要线程没有同时访问同一个地址就没有问题。
但是直接回答你的问题,不,它不是线程安全的,所以你不能没有任何错误地锁定它。