20

我有一个 std::map 用于将值(字段 ID)映射到人类可读的字符串。当我的程序在任何其他线程启动之前启动时,这个映射被初始化一次,之后它就再也不会被修改了。现在,我给每个线程自己的这个(相当大的)映射副本,但这显然是对内存的低效使用,并且会减慢程序启动速度。所以我想给每个线程一个指向映射的指针,但这会引发线程安全问题。

如果我所做的只是使用以下代码从地图中读取:

std::string name;
//here N is the field id for which I want the human readable name
unsigned field_id = N; 
std::map<unsigned,std::string>::const_iterator map_it;

// fields_p is a const std::map<unsigned, std::string>* to the map concerned.
// multiple threads will share this.
map_it = fields_p->find(field_id);
if (map_it != fields_p->end())
{
    name = map_it->second;
}
else
{
    name = "";
}

这会起作用还是从多个线程读取 std::map 是否存在问题?

注意:我目前正在使用 Visual Studio 2008,但我希望它能够在大多数主要的 STL 实现中工作。

更新:为 const 正确性编辑了代码示例。

4

4 回答 4

16

只要您的地图保持不变,这将适用于多个线程。您使用的地图实际上是不可变的,因此任何查找实际上都会在不会更改的地图中进行查找。

这是一个相关链接:http ://www.sgi.com/tech/stl/thread_safety.html

STL 的 SGI 实现是线程安全的,仅在对不同容器的同时访问是安全的,对共享容器的同时读取访问是安全的意义上说。如果多个线程访问单个容器,并且至少有一个线程可能写入,则用户负责确保容器访问期间线程之间的互斥。

您属于“对共享容器的同时读取访问”类别。

注意:这适用于 SGI 实现。您需要检查是否使用其他实现。据我所知,在似乎被广泛用作替代方案的两种实现中,STLPort 具有内置的线程安全性。不过,我不知道 Apache 的实现。

于 2009-12-04T10:48:26.673 回答
9

应该没问题。const如果您想记录/强制执行只读行为,您可以使用对它的引用。

find请注意,即使您确实只使用 const 方法(一个非常不正常的实现可能声明树是可变的),也不能保证正确性(原则上地图可以选择在调用 时重新平衡自身)。然而,这在实践中似乎不太可能。

于 2009-12-04T10:52:45.910 回答
3

是的。

请参阅有关 std::set 的相同问题的相关帖子:

C++ std::set 线程安全吗?

于 2009-12-04T11:45:49.453 回答
0

对于 MS STL 实施

C++ 标准库中的线程安全

以下线程安全规则适用于 C++ 标准库中的所有类,包括 shared_ptr,如下所述。有时会提供更强的保证——例如,标准 iostream 对象,如下所述,以及专门用于多线程的类型,如 .

一个对象是线程安全的,可以从多个线程中读取。例如,给定一个对象 A,从线程 1 和线程 2 同时读取 A 是安全的。

于 2020-01-16T04:35:13.760 回答