我知道标准库中的容器并不是线程安全的。在此之前,我一直认为一个容器(比如std::list
类型的容器)不能被多个线程并发访问(其中一些线程可能会修改容器)。但现在看来,它有比眼前更多的东西;一些更微妙的东西,一些不那么明显的东西,至少对我来说是这样。
例如,考虑这个函数,它按值接受第一个参数
void log(std::string msg, severity s, /*...*/)
{
return; //no code!
}
这个线安全吗?
起初,它似乎是线程安全的,因为函数主体没有访问共享的可修改资源,因此线程是安全的。再想一想,当调用这样一个函数时,会创建一个std::string
类型的对象,这是第一个参数,我认为这个对象的构造不是线程安全的,因为它内部使用std::allocator
,我认为它不是线程安全的。因此,调用这样的函数也不是线程安全的。但如果它是正确的,那么这是怎么说的:
void f()
{
std::string msg = "message"; //is it thread-safe? it doesn't seem so!
}
我走得对吗?我们可以在多线程程序中使用std::string
(或任何内部使用std::allocator
的容器)吗?
--我专门说的容器是局部变量,而不是共享对象。
我搜索了谷歌,发现了许多类似的疑问,没有具体的答案。我所面对的问题与他的问题相似:
请同时考虑C++03和C++11。
发布于 2012-03-01 10:41:39
在C++11中,std::allocator
是线程安全的。从定义上看:
20.6.9.1/6:备注:通过调用
::operator new(std::size_t)
获得存储
从::operator new
的定义
18.6.1.4:
operator new
和operator delete
的库版本、全局operator new
和operator delete
的用户替换版本以及C标准库函数calloc
、malloc
、realloc
和free
不应由于来自不同线程的并发调用而引入数据竞赛(1.10)。
C++03没有线程的概念,所以任何线程安全都是特定于实现的;您必须参考实现的文档来查看它所提供的保证(如果有的话)。由于您使用的是微软的实现,此页说从多个线程写入同一个类的多个容器对象是安全的,这意味着std::allocator
是线程安全的。
发布于 2012-03-01 10:50:51
在C++11中,对于默认的分配器,这将在以下文件中得到解决:
20.6.9.1分配程序成员allocator.members 除析构函数外,默认分配程序的成员函数不应由于来自不同线程的对这些成员函数的并发调用而引入数据竞赛(1.10)。对分配或释放某一特定存储单元的这些功能的调用应以单个总顺序进行,而每一次取消分配调用都应发生在此顺序中的下一次分配(如果有的话)之前。
任何用户提供的分配器如果要跨不同的线程使用,都必须保持相同的约束。
当然,对于该标准的早期版本,没有提到这一点,因为他们没有谈到多线程。如果一个实现支持多线程(像许多人或大多数人一样),那么它将负责处理这些问题。类似于实现为C和C++提供线程安全的malloc()
(和其他库函数)的方式,尽管之前的标准没有提到这一点。
发布于 2012-03-01 10:52:33
正如你可能已经想到的,不会有一个简单的答案是或不是。不过,我认为这可能有帮助:
我逐字引述:
5.6 libstdc++-v3线程安全吗? 当满足以下所有条件时,libstdc++-v3力求实现线程安全: 该系统的libc本身是线程安全的,gcc -v报告了一个线程模型,而不是‘单’的,在3.3之前,只有一个非一般实现为所讨论的体系结构存在一个非一般实现。
https://stackoverflow.com/questions/9521879
复制相似问题