【发布时间】:2012-09-07 23:27:38
【问题描述】:
我早就知道 GCC 对 std::string 使用 COW (Copy-On-Write),这使得在多线程程序中无法使用 std::string。但据我所知,C++11 禁止使用 COW 的实现,因为线程现在由标准定义,并且移动语义几乎已经过时了对 COW 的需求。
现在,GCC 4.6 实现了大量的 C++11 标准。然而,实现似乎仍然使用 COW 语义。我写的一个多线程应用程序中随机出现的神秘段错误引起了我的注意。我已经通过以下测试代码确认这实际上是一个 COW 问题:
#include <iostream>
#include <string>
#include <cassert>
#include <thread>
using namespace std;
int main()
{
std::string orig = "abc";
std::string copy = orig;
std::cout << (void*) orig.data() << ", " << (void*) copy.data() << endl;
assert(orig.data() == copy.data());
}
编辑:注意此处包含 <thread> 标头,证明这是一个 C++11 程序。这是一个link to ideone 确认我在说什么,(至少对于 ideone 使用的 GCC 4.5.1)
我不记得为什么,但出于某种原因,我的印象是std=c++0x 标志会消除 COW 语义,但事实并非如此。上述代码中的断言是成功的,即使带有 --std=c++0x 标志。所以基本上,从 GCC 4.6 开始,std::string 在多线程应用程序中仍然不可用。
有什么方法可以禁用 COW 语义?还是在 GCC 修复此问题之前我需要暂时使用 std::vector<char>?
【问题讨论】:
-
不可能在多线程程序中使用?当然不是。简单地不要从多个线程写入字符串,无论如何这是一个(非常)坏主意。 (是的,它比这稍微复杂一些,但并不多。)
-
@KonradRudolph 的想法是应该可以独立写入字符串的副本。
-
@KonradRudolph - 如果您从另一个线程中更改的字符串中读取,您仍然会遇到麻烦,因为在您观看时复杂对象的状态正在发生变化,导致后果取决于确切的实现.当不止一个线程拥有它时,你真的需要完全避免写入它。
-
我认为 OP 的观点是 GCC 违反了规范。他的代码应该可以正常工作。
-
AFAIK Gnu 使用原子操作在 std::string 中进行引用计数。这对于线程安全来说应该足够了。你能描述一下你认为这种安全可以被破坏的情景吗?
标签: c++ string gcc c++11 thread-safety