2011-12-06 22 views
11

Al hacer la transición de mi código a C++ 11, me gustaría convertir mi código pthread a std :: thread. Sin embargo, parece que estoy obteniendo condiciones de carrera falsas en programas muy simples en drd y en helgrind.Estado actual de soporte drd y helgrind para std :: thread

#include <thread> 

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

fragmento de salida Helgrind - También consigo errores similares en DRD, utilizando gcc 4.6.1, 3.7.0 valgrind en Ubuntu 11.11 amd64.

Mis preguntas son: cheque

  • cordura: ¿Estoy haciendo algo mal? ¿Otros están obteniendo informes falsos similares sobre simples programas std :: thread?
  • ¿Qué usuarios actuales de std :: thread usan para detectar condiciones de carrera?

Soy reacio a exportar un montón de código de pthread al std::thread hasta que algunas herramientas cruciales como helgrind/drd hayan alcanzado.

==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: [email protected]@GLIBC_2.2.5 (createthread.c:256) 
==19347== by 0x4C2B3DA: pthread_create_WRK (hg_intercepts.c:255) 
==19347== by 0x4C2B55E: [email protected]* (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== 

Respuesta

12

std :: thread utiliza un puntero compartido internamente. Lo que está viendo son falsos positivos en el recuento de referencias de ese objeto puntero compartido. Puede evitar estos falsos positivos agregando las cuatro líneas de código que se muestran a continuación en cada archivo fuente justo antes de que el encabezado C++ incluya directivas. Nota: esto solo funciona con la versión de libstdC++ incluida con gcc 4.6.0 o posterior.

#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 

Para obtener más información, consulta la sección de datos de carreras de caza en el libstdC++ manual (http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html).

+0

+1 punta fantástica! Definitivamente voy a probarlo, gracias. – kfmfe04

+2

Nota: acaba de descubrir que hay un error en libstdC++ que no permite que std :: thread se anote correctamente - ver también [gcc error 51504] (http://gcc.gnu.org/bugzilla/show_bug.cgi ? id = 51504). – user251384

3

Lo más probable es que lo que está viendo son falsos positivos. Estoy observando un comportamiento similar en mi código.

En concreto, las advertencias parecen estar relacionadas con la implementación de la clase de punteros compartidos, y entiendo que en su plataforma (supongo que es x86/x86-64?) GCC está utilizando instrucciones optimizadas de ensamblaje atómico en el puntero compartido maquinaria de recuento de referencia. El problema es que valgrind puede detectar errores cuando utiliza las primitivas POSIX (bloqueos, mutexes, etx.), Pero no puede hacer frente a las primitivas de nivel inferior.

Lo que he hecho hasta ahora es simplemente filtrar desde la salida de valgrind las advertencias (posiblemente podría escribir algún archivo de supresión que haga el trabajo de la manera correcta).

+0

thx para la verificación de la cordura - Salté en la conversión de pthreads a std :: thread. Con la excepción de scoping std :: conditional_variable correctamente, la mayor parte del porting fue indolora (lo cual no es sorprendente, ya que pthreads no están tan debajo). Resolveré algunos errores drd/helgrind con supresiones en el día siguiente o dos y los agregaré al OP. – kfmfe04

1

Si utiliza boost puede activar el uso de pthreads primitives en lugar de operaciones atómicas para punteros compartidos. A continuación, puede usar una versión de su código compilada con BOOST_SP_USE_PTHREADS para el análisis helgrind, y no obtendrá los errores porque helgrind entiende las primitivas pthreads.

Consulte http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety para obtener más información.

Cuestiones relacionadas