在使用 clang 的线程清理器时,我们注意到数据竞争警告。我们认为这是由于 std::string 的写时复制技术不是线程安全的,但我们可能错了。我们将看到的警告减少到此代码:
void test3() {
std::unique_ptr<std::thread> thread;
{
auto output = make_shared<string>();
std::string str = "test";
thread.reset(new std::thread([str, output]() { *output += str; }));
// The str string now goes out of scope but due to COW
// the captured string may not have the copy of the content yet.
}
thread->join();
}
在启用线程清理器的情况下编译时:
clang++ -stdlib=libc++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp
或
clang++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp
当多次运行时,它最终会产生这个警告:
WARNING: ThreadSanitizer: data race (pid=30829)
Write of size 8 at 0x7d0c0000bef8 by thread T62:
#0 operator delete(void*) <null>:0
...
Previous write of size 1 at 0x7d0c0000befd by thread T5:
#0 std::__1::char_traits<char>::assign(char&, char const&) string:639
...
这是线程清理程序的误报还是真正的数据竞争?如果是后者, 是否可以在不更改代码的情况下解决它(例如,通过将一些标志传递给编译器),这是字符串实现(或其他)中的已知错误吗?
更新:clang --version 输出:
Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)
Target: x86_64-pc-linux-gnu
Thread model: posix
更新:The cpp我用来重现此警告。
最佳答案
[编辑] 下面的假设被证明是错误的,请参阅评论中的链接。 T5,而不是 T62 是上面代码中产生的线程。
<罢工> 了解线程 ID 会很有用,但我假设 T5 是主线程,T62 是衍生线程。看起来拷贝是在主线程上制作的(在新线程生成之前)并在新线程上销毁(显然)。这是安全的,因为新线程在存在之前不能与主线程竞争。
因此,这是一个线程清理程序错误。未能检查上一次写入时是否存在线程 T62。
关于c++ - 在多线程环境中使用 std::string 时 Clang 的线程清理器警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27730158/