标准容器作为多线程应用程序中的局部变量

Naw*_*waz 12 c++ string multithreading vector allocator

我知道标准库中的容器不是线程安全的.我以前认为一个容器,比如说类型std::list,不能同时被多个线程访问(其中一些可能会修改容器).但现在似乎还有更多的东西比满足眼睛; 更微妙的东西,不那么明显的东西,至少对我而言.

例如,考虑这个函数,它接受值的第一个参数:

void log(std::string msg, severity s, /*...*/) 
{
   return; //no code!
}
Run Code Online (Sandbox Code Playgroud)

这是线程安全的吗?

起初,似乎它是线程安全的,因为函数体不访问共享的可修改资源,因此是线程安全的.在第二个想法,我发现,当调用这样的函数时,std::string将创建一个类型的对象,这是第一个参数,我认为这个对象的构造不是线程安全的,因为它在内部使用std::allocator,我相信这不是线程安全的.因此,调用这样的函数也不是线程安全的.但如果它是正确的,那么这个怎么样:

void f()
{
   std::string msg = "message"; //is it thread-safe? it doesn't seem so!
}
Run Code Online (Sandbox Code Playgroud)

我是对的吗?我们可以在多线程程序中使用std::string(或任何std::allocator内部使用的容器)吗?

我特别将容器称为局部变量,而不是共享对象.

我搜索谷歌,发现了许多类似的疑虑,没有具体的答案.我面临与他类似的问题:

请考虑C++ 03和C++ 11.

Mik*_*our 7

在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没有线程概念,因此任何线程安全都是特定于实现的; 您必须参考您的实施文档,看看它提供了什么保证,如果有的话.由于您正在使用Microsoft的实现,因此该页面表示从多个线程写入同一类的多个容器对象是安全的,这意味着它std::allocator是线程安全的.


Mic*_*urr 5

在C++ 11中,这将针对默认分配器解决:

20.6.9.1分配器成员[allocator.members]

除了析构函数之外,默认分配器的成员函数不应引入数据争用(1.10)作为对来自不同线程的那些成员函数的并发调用的结果.对分配或取消分配特定存储单元的这些功能的调用应在单个总顺序中进行,并且每个这样的重新分配调用应在该顺序中的下一个分配(如果有的话)之前发生.

如果要在不同的线程中使用,任何用户提供的分配器都必须保持相同的约束.

当然,对于该标准的早期版本,由于他们没有谈论多线程,因此没有任何说法.如果一个实现是支持多线程(尽可能多或多数),它将负责处理这些问题.类似于实现malloc()为C和C++ 提供线程安全(和其他库函数)的方式,即使最近之前的标准没有说明这一点.