当我将代码转换为C ++ 11时,我非常希望将我的pthread代码转换为std :: thread。但是,我似乎在drd和helgrind中的非常简单的程序中获得了错误的竞争条件。
#include <thread>
int main(int argc, char** argv)
{
std::thread t( []() { } );
t.join();
return 0;
}
Helgrind输出片段 - 我在drd中也遇到了类似的错误,在Ubuntu 11.11 amd64上使用gcc 4.6.1,valgrind 3.7.0。
我的问题是:
我不愿意将大量代码从pthread移植到std::thread
,直到像helgrind / drd这样的关键工具赶上来。
==19347== ---Thread-Announcement------------------------------------------
==19347==
==19347== Thread #1 is the program's root thread
==19347==
==19347== ---Thread-Announcement------------------------------------------
==19347==
==19347== Thread #2 was created
==19347== at 0x564C85E: clone (clone.S:77)
==19347== by 0x4E37E7F: do_clone.constprop.3 (createthread.c:75)
==19347== by 0x4E39604: pthread_create@@GLIBC_2.2.5 (createthread.c:256)
==19347== by 0x4C2B3DA: pthread_create_WRK (hg_intercepts.c:255)
==19347== by 0x4C2B55E: pthread_create@* (hg_intercepts.c:286)
==19347== by 0x50BED02: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==19347== by 0x400D51: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== ----------------------------------------------------------------
==19347==
==19347== Possible data race during write of size 8 at 0x5B8E060 by thread #1
==19347== Locks held: none
==19347== at 0x40165E: _ZNSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEED1Ev (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401895: _ZNKSt19_Sp_destroy_inplaceINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEEclEPS6_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x4016D8: _ZNSt19_Sp_counted_deleterIPNSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESt19_Sp_destroy_inplaceIS6_ESaIS6_ELN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401B83: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401B3E: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401A93: std::__shared_ptr<std::thread::_Impl_base, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401AAD: std::shared_ptr<std::thread::_Impl_base>::~shared_ptr() (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400D5D: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== This conflicts with a previous read of size 8 by thread #2
==19347== Locks held: none
==19347== at 0x50BEABE: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==19347== by 0x4C2B547: mythread_wrapper (hg_intercepts.c:219)
==19347== by 0x4E38EFB: start_thread (pthread_create.c:304)
==19347== by 0x564C89C: clone (clone.S:112)
==19347==
==19347== Address 0x5B8E060 is 32 bytes inside a block of size 64 alloc'd
==19347== at 0x4C29059: operator new(unsigned long) (vg_replace_malloc.c:287)
==19347== by 0x4012E9: _ZN9__gnu_cxx13new_allocatorISt23_Sp_counted_ptr_inplaceINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaIS8_ELNS_12_Lock_policyE2EEE8allocateEmPKv (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x40117C: _ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EEC1INSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaISA_EIS9_EEESt19_Sp_make_shared_tagPT_RKT0_DpOT1_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x4010B9: _ZNSt12__shared_ptrINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEELN9__gnu_cxx12_Lock_policyE2EEC1ISaIS6_EIS5_EEESt19_Sp_make_shared_tagRKT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401063: _ZNSt10shared_ptrINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEEC1ISaIS6_EIS5_EEESt19_Sp_make_shared_tagRKT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x401009: _ZSt15allocate_sharedINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEESaIS6_EIS5_EESt10shared_ptrIT_ERKT0_DpOT1_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400EF7: _ZSt11make_sharedINSt6thread5_ImplISt12_Bind_resultIvFZ4mainEUlvE_vEEEEIS5_EESt10shared_ptrIT_EDpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400E17: _ZNSt6thread15_M_make_routineISt12_Bind_resultIvFZ4mainEUlvE_vEEEESt10shared_ptrINS_5_ImplIT_EEEOS7_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400D2B: _ZNSt6threadC1IZ4mainEUlvE_IEEEOT_DpOT0_ (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347== by 0x400C60: main (in /mnt/home/kfeng/dev/robolab/cpp/sbx/sandbox)
==19347==
==19347== ----------------------------------------------------------------
==19347==
答案 0 :(得分:13)
std :: thread在内部使用共享指针。您所看到的是该共享指针对象的引用计数的误报。您可以通过在C ++标头包含指令之前在每个源文件中添加下面显示的四行代码来避免这些误报。注意:这仅适用于gcc 4.6.0或更高版本中包含的libstdc ++版本。
#include <valgrind/drd.h>
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) ANNOTATE_HAPPENS_BEFORE(addr)
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) ANNOTATE_HAPPENS_AFTER(addr)
#define _GLIBCXX_EXTERN_TEMPLATE -1
有关更多信息,另请参阅libstdc ++手册(http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html)中的数据竞争搜索部分。
答案 1 :(得分:3)
你看到的最有可能是误报。我在我的代码中观察到类似的行为。
具体来说,警告似乎与共享指针类的实现有关,我的理解是在你的平台上(我认为是x86 / x86-64?)GCC在共享指针引用中使用优化的原子汇编指令计数机器。问题是valgrind能够在使用POSIX原语(锁,互斥,等等)时检测错误,但它无法处理较低级别的原语。
到目前为止我所做的只是简单地从valgrind的输出中过滤掉警告(可能你可以编写一些以正确方式完成工作的抑制文件)。
答案 2 :(得分:1)
如果使用boost,则可以打开使用pthreads原语而不是共享指针的原子操作。然后,您可以使用使用BOOST_SP_USE_PTHREADS编译的代码版本进行helgrind分析,并且您不会得到错误,因为helgrind了解pthreads原语。
有关详细信息,请参阅http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety。