#include <iostream>
#include <sstream>
#include <thread>
using namespace std;
int main()
{
auto runner = []() {
ostringstream oss;
for (int i=0; i<100000; ++i)
oss << i;
};
thread t1(runner), t2(runner);
t1.join(); t2.join();
}
在g++6.2.1中编译上面的代码,然后运行它valgrind --tool=helgrind ./a.out
。赫尔格琳德会抱怨:
==5541== ----------------------------------------------------------------
==5541==
==5541== Possible data race during read of size 1 at 0x51C30B9 by thread #3
==5541== Locks held: none
==5541== at 0x4F500CB: widen (locale_facets.h:875)
==5541== by 0x4F500CB: widen (basic_ios.h:450)
==5541== by 0x4F500CB: fill (basic_ios.h:374)
==5541== by 0x4F500CB: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5541== by 0x400CD0: main::{lambda()#1}::operator()() const (43.cpp:12)
==5541== by 0x4011F7: void std::_Bind_simple<main::{lambda()#1} ()>::_M_invoke<>(std::_Index_tuple<>) (functional:1391)
==5541== by 0x401194: std::_Bind_simple<main::{lambda()#1} ()>::operator()() (functional:1380)
==5541== by 0x401173: std::thread::_State_impl<std::_Bind_simple<main::{lambda()#1} ()> >::_M_run() (thread:197)
==5541== by 0x4EF858E: execute_native_thread_routine (thread.cc:83)
==5541== by 0x4C31A04: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5541== by 0x56E7453: start_thread (in /usr/lib/libpthread-2.24.so)
==5541== by 0x59E57DE: clone (in /usr/lib/libc-2.24.so)
==5541==
==5541== This conflicts with a previous write of size 8 by thread #2
==5541== Locks held: none
==5541== at 0x4EF3B1F: do_widen (locale_facets.h:1107)
==5541== by 0x4EF3B1F: std::ctype<char>::_M_widen_init() const (ctype.cc:94)
==5541== by 0x4F501B7: widen (locale_facets.h:876)
==5541== by 0x4F501B7: widen (basic_ios.h:450)
==5541== by 0x4F501B7: fill (basic_ios.h:374)
==5541== by 0x4F501B7: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5541== by 0x400CD0: main::{lambda()#1}::operator()() const (43.cpp:12)
==5541== by 0x4011F7: void std::_Bind_simple<main::{lambda()#1} ()>::_M_invoke<>(std::_Index_tuple<>) (functional:1391)
==5541== by 0x401194: std::_Bind_simple<main::{lambda()#1} ()>::operator()() (functional:1380)
==5541== by 0x401173: std::thread::_State_impl<std::_Bind_simple<main::{lambda()#1} ()> >::_M_run() (thread:197)
==5541== by 0x4EF858E: execute_native_thread_routine (thread.cc:83)
==5541== by 0x4C31A04: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5541== Address 0x51c30b9 is 89 bytes inside data symbol "_ZN12_GLOBAL__N_17ctype_cE"
看来两个线程都调用了locale_facet.h:widen
这导致了数据竞争,因为该函数中似乎没有同步,即使operator <<
被调用于两个不同的ostringstream
目的。所以我想知道这是否真的是一场数据竞赛还是只是误报helgrind
.
Update:我承认在回答之前我没有完全阅读问题,所以我自己进行了研究。
TL;DR
这里有可变的成员变量可能会导致竞争条件。 ios 每个语言环境都有静态变量,这些静态变量延迟加载(首次需要时初始化)查找表。如果您想避免并发问题,请确保在加入线程之前初始化区域设置,以便任何线程操作只能读取这些查找表。
细节
当一个流被初始化时,它会填充一个指针,该指针加载到语言环境的正确 ctype 中(请参阅 _M_ctype):https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/basic_ios.h#L273 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/basic_ios.h#L273
该错误指的是:https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/locale_facets.h#L875 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/locale_facets.h#L875
如果两个线程同时初始化相同的区域设置,这可能是竞争条件。
这应该是线程安全的(尽管它仍然可能会出错):
// Force ctype to be initialized in the base thread before forking
ostringstream dump;
dump << 1;
auto runner = []() {
ostringstream oss;
for (int i=0; i<100000; ++i)
oss << i;
};
thread t1(runner), t2(runner);
t1.join(); t2.join();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)