Текущее состояние поддержки drd и helgrind для std :: thread - PullRequest
11 голосов
/ 06 декабря 2011

Когда я перевожу свой код на C ++ 11, я бы очень хотел преобразовать свой код pthread в std :: thread. Тем не менее, я, кажется, получаю ложные условия гонки на очень простых программах в drd и helgrind.

#include <thread>

int main(int argc, char** argv)
{
    std::thread t( []() { } );
    t.join();
    return 0;
}

Фрагмент вывода Helgrind - я также получаю похожие ошибки в drd, используя gcc 4.6.1, valgrind 3.7.0 в Ubuntu 11.11 amd64.

Мои вопросы:

  • проверка работоспособности: я делаю что-то не так? Получают ли другие подобные ложные отчеты о простых программах std :: thread?
  • Что нынешние пользователи std :: thread используют для обнаружения условий гонки?

Я не хочу переносить тонну кода с 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==

Ответы [ 3 ]

13 голосов
/ 10 декабря 2011

std :: thread использует совместно используемый указатель. То, что вы видите, это ложные срабатывания на счетчике ссылок этого общего объекта указателя. Вы можете избежать этих ложных срабатываний, добавив четыре строки кода, показанные ниже, в каждом исходном файле непосредственно перед тем, как заголовок C ++ включает директивы. Примечание: это работает только с версией libstdc ++, включенной в gcc 4.6.0 или новее.

#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).

3 голосов
/ 06 декабря 2011

Скорее всего, вы видите ложные срабатывания.Я наблюдаю похожее поведение в моем коде.

В частности, кажется, что предупреждения связаны с реализацией класса общего указателя, и я понимаю, что на вашей платформе (который я предполагаю, x86 / x86-64?) GCC использует оптимизированную инструкцию атомарной сборки в подсчете ссылок общего указателя.Проблема в том, что valgrind способен обнаруживать ошибки при использовании примитивов POSIX (блокировки, мьютексы и т. Д.), Но он не может справиться с примитивами более низкого уровня.

Что я сделал до сих пор, так этопросто отфильтровывать из вывода valgrind предупреждения (возможно, вы могли бы написать какой-нибудь файл подавления, который выполняет работу надлежащим образом).

1 голос
/ 09 августа 2013

Если вы используете 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 для получения дополнительной информации.

...