2017-01-29 3 views
0

helgrind를 C++ 11 미래 및 패키지 태스크와 함께 사용하면 오탐이라고 생각합니다. 다음은 CentOS6 시스템에서 gcc-6.3.0 및 valgrind-3.12입니다. 필자는 문서의 조언에 따라 주석을 제공하려고 노력했습니다. 내가 잘못 했니? 가양 성을 피하기 위해 무엇을해야합니까? 아니면 정말로 경주가 있습니까?helgrind (valgrind)를 C++ 11 future와 함께 사용할 수 있습니다.

drdws0134$ cat hthread.cpp 
#include <valgrind/helgrind.h> 
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) ANNOTATE_HAPPENS_BEFORE(addr) 
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) ANNOTATE_HAPPENS_BEFORE(addr) 
#define _GLIBCXX_EXTERN_TEMPLATE -1 

#include "thread.cc" 

drdws0134$ cat bleep.cpp 
#include <valgrind/helgrind.h> 
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(addr) ANNOTATE_HAPPENS_BEFORE(addr) 
#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(addr) ANNOTATE_HAPPENS_BEFORE(addr) 
#define _GLIBCXX_EXTERN_TEMPLATE -1 

#include <future> 
#include <iostream> 

std::packaged_task<int()> pt; 

void call_pt(){ 
    pt(); 
} 

int main(int, char **){ 
    pt = std::packaged_task<int()>([](){ return 91; }); 
    auto fut = pt.get_future(); 
    std::thread t(call_pt); 
    std::cout << fut.get() << "\n"; 
    t.join(); 
    return 0; 
} 

drdws0134$ ./x make bleep 
g++ -I/proj/desres/root/CentOS6/x86_64/valgrind/3.12.0-01/include -std=c++14 -pthread -ggdb -O0 -c -o hthread.o hthread.cpp 
g++ -I/proj/desres/root/CentOS6/x86_64/valgrind/3.12.0-01/include -std=c++14 -pthread -ggdb -O0 -pthread bleep.cpp hthread.o -o bleep 
drdws0134$ ./bleep 
91 
drdws0134$ which valgrind 
valgrind is /proj/desres/root/CentOS6/x86_64/valgrind/3.12.0-01/bin/valgrind 
valgrind is /usr/bin/valgrind 
drdws0134$ valgrind --tool=helgrind ./bleep 
==11476== Helgrind, a thread error detector 
==11476== Copyright (C) 2007-2015, and GNU GPL'd, by OpenWorks LLP et al. 
==11476== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info 
==11476== Command: ./bleep 
==11476== 
==11476== ---Thread-Announcement------------------------------------------ 
==11476== 
==11476== Thread #1 is the program's root thread 
==11476== 
==11476== ---Thread-Announcement------------------------------------------ 
==11476== 
==11476== Thread #2 was created 
==11476== at 0x321B8E8A6E: clone (in /lib64/libc-2.12.so) 
==11476== by 0x321C00690F: do_clone.clone.0 (in /lib64/libpthread-2.12.so) 
==11476== by 0x321C006E6C: [email protected]@GLIBC_2.2.5 (in /lib64/libpthread-2.12.so) 
==11476== by 0x4A0C553: pthread_create_WRK (hg_intercepts.c:427) 
==11476== by 0x4A0D637: [email protected]* (hg_intercepts.c:460) 
==11476== by 0x407897: __gthread_create(unsigned long*, void* (*)(void*), void*) (gthr-default.h:662) 
==11476== by 0x407C0F: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (thread.cc:163) 
==11476== by 0x4056C0: std::thread::thread<void (&)()>(void (&)()) (thread:136) 
==11476== by 0x402820: main (bleep.cpp:18) 
==11476== 
==11476== ---------------------------------------------------------------- 
==11476== 
==11476== Possible data race during read of size 8 at 0x51F0C98 by thread #1 
==11476== Locks held: none 
==11476== at 0x405AF8: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::get() const (unique_ptr.h:308) 
==11476== by 0x404CF3: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::operator*() const (unique_ptr.h:294) 
==11476== by 0x404538: std::__future_base::_State_baseV2::wait() (future:329) 
==11476== by 0x4064F6: std::__basic_future<int>::_M_get_result() const (future:687) 
==11476== by 0x405729: std::future<int>::get() (future:766) 
==11476== by 0x40282C: main (bleep.cpp:19) 
==11476== 
==11476== This conflicts with a previous write of size 8 by thread #2 
==11476== Locks held: none 
==11476== at 0x406EC6: std::enable_if<std::__and_<std::is_move_constructible<std::__future_base::_Result_base*>, std::is_move_assignable<std::__future_base::_Result_base*> >::value, void>::type std::swap<std::__future_base::_Result_base*>(std::__future_base::_Result_base*&, std::__future_base::_Result_base*&) (move.h:191) 
==11476== by 0x406CC2: std::_Tuple_impl<0ul, std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>::_M_swap(std::_Tuple_impl<0ul, std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>&) (tuple:331) 
==11476== by 0x406774: std::tuple<std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>::swap(std::tuple<std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>&) (tuple:1215) 
==11476== by 0x405E68: void std::swap<std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>(std::tuple<std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>&, std::tuple<std::__future_base::_Result_base*, std::__future_base::_Result_base::_Deleter>&) (tuple:1548) 
==11476== by 0x405224: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::swap(std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>&) (unique_ptr.h:355) 
==11476== by 0x404A26: std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*) (future:538) 
==11476== by 0x406746: void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&) (functional:227) 
==11476== by 0x405B6B: std::result_of<void (std::__future_base::_State_baseV2::*&&(std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&))(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*)>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&) (functional:251) 
==11476== Address 0x51f0c98 is 24 bytes inside a block of size 64 alloc'd 
==11476== at 0x4A07526: operator new(unsigned long) (vg_replace_malloc.c:334) 
==11476== by 0x40313F: __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (new_allocator.h:104) 
==11476== by 0x402FC4: std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2>&, unsigned long) (alloc_traits.h:416) 
==11476== by 0x402DEF: std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2> > >(std::__allocated_ptr&) (allocated_ptr.h:103) 
==11476== by 0x402C7D: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>*, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr_base.h:613) 
==11476== by 0x402BCE: std::__shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr_base.h:1100) 
==11476== by 0x402AFF: std::shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()> >::shared_ptr<main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr.h:319) 
==11476== by 0x402A5C: std::shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()> > std::allocate_shared<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr.h:620) 
==11476== by 0x4029E5: std::shared_ptr<std::__future_base::_Task_state_base<int()> > std::__create_task_state<int(), main::{lambda()#1}, std::allocator<int> >(main::{lambda()#1}&&, std::allocator<int> const&) (future:1451) 
==11476== by 0x402969: std::packaged_task<int()>::packaged_task<main::{lambda()#1}, std::allocator<int>, void>(std::allocator_arg_t, std::allocator<int> const&, main::{lambda()#1}&&) (future:1503) 
==11476== by 0x4028FD: std::packaged_task<int()>::packaged_task<main::{lambda()#1}, void>(main::{lambda()#1}&&) (future:1493) 
==11476== by 0x4027E1: main (bleep.cpp:16) 
==11476== Block was alloc'd by thread #1 
==11476== 
==11476== ---------------------------------------------------------------- 
==11476== 
==11476== Possible data race during read of size 4 at 0x51F0D10 by thread #1 
==11476== Locks held: none 
==11476== at 0x40573A: std::future<int>::get() (future:766) 
==11476== by 0x40282C: main (bleep.cpp:19) 
==11476== 
==11476== This conflicts with a previous write of size 4 by thread #2 
==11476== Locks held: none 
==11476== at 0x40761B: std::__future_base::_Result<int>::_M_set(int&&) (future:249) 
==11476== by 0x403C70: std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<int>, std::__future_base::_Result_base::_Deleter>, std::_Bind_simple<std::reference_wrapper<main::{lambda()#1}>()>, int>::operator()() const (future:1325) 
==11476== by 0x403ACE: std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>(), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<int>, std::__future_base::_Result_base::_Deleter>, std::_Bind_simple<std::reference_wrapper<main::{lambda()#1}>()>, int> >::_M_invoke(std::_Any_data const&) (functional:1717) 
==11476== by 0x405264: std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>::operator()() const (functional:2127) 
==11476== by 0x404A08: std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*) (future:533) 
==11476== by 0x406746: void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&) (functional:227) 
==11476== by 0x405B6B: std::result_of<void (std::__future_base::_State_baseV2::*&&(std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&))(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*)>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&) (functional:251) 
==11476== by 0x404D7B: void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>()>*&&, bool*&&)::{lambda()#1}::operator()() const (mutex:602) 
==11476== Address 0x51f0d10 is 16 bytes inside a block of size 24 alloc'd 
==11476== at 0x4A07526: operator new(unsigned long) (vg_replace_malloc.c:334) 
==11476== by 0x4071D6: std::unique_ptr<std::__future_base::_Result<int>, std::__future_base::_Result_base::_Deleter> std::__future_base::_S_allocate_result<int, int>(std::allocator<int> const&) (future:294) 
==11476== by 0x40713D: std::__future_base::_Task_state_base<int()>::_Task_state_base<std::allocator<int> >(std::allocator<int> const&) (future:1373) 
==11476== by 0x403280: std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>::_Task_state<{lambda()#1}>({lambda()#1}&&, main::{lambda()#1} const&) (future:1399) 
==11476== by 0x4031F1: void __gnu_cxx::new_allocator<int>::construct<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, {lambda()#1}, main::{lambda()#1} const&>(std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>*, {lambda()#1}&&, main::{lambda()#1} const&) (new_allocator.h:120) 
==11476== by 0x4030F7: void std::allocator_traits<std::allocator<int> >::construct<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, {lambda()#1}, std::allocator<int> const&>(std::allocator<int>&, std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>*, {lambda()#1}&&, std::allocator<int> const&) (alloc_traits.h:455) 
==11476== by 0x402F31: std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, (__gnu_cxx::_Lock_policy)2>::_Sp_counted_ptr_inplace<{lambda()#1}, main::{lambda()#1} const&>(main::{lambda()#1}, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr_base.h:520) 
==11476== by 0x402CF7: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>*, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr_base.h:615) 
==11476== by 0x402BCE: std::__shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr_base.h:1100) 
==11476== by 0x402AFF: std::shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()> >::shared_ptr<main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(std::_Sp_make_shared_tag, main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr.h:319) 
==11476== by 0x402A5C: std::shared_ptr<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()> > std::allocate_shared<std::__future_base::_Task_state<main::{lambda()#1}, std::allocator<int>, int()>, main::{lambda()#1}, {lambda()#1}, main::{lambda()#1} const&>(main::{lambda()#1} const&, {lambda()#1}&&, main::{lambda()#1} const&) (shared_ptr.h:620) 
==11476== by 0x4029E5: std::shared_ptr<std::__future_base::_Task_state_base<int()> > std::__create_task_state<int(), main::{lambda()#1}, std::allocator<int> >(main::{lambda()#1}&&, std::allocator<int> const&) (future:1451) 
==11476== Block was alloc'd by thread #1 
==11476== 
91 
==11476== 
==11476== For counts of detected and suppressed errors, rerun with: -v 
==11476== Use --history-level=approx or =none to gain increased speed, at 
==11476== the cost of reduced accuracy of conflicting-access information 
==11476== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 
drdws0134$ 

답변

0

.

나는이 문제를 우연히 발견하고 거의 당신과 동일한 질문을 작성하려고했습니다. g ++/libstdC++ 6.2.0 및 개발 valgrind (> 3.9.0)를 사용하고 있습니다.

문제는 g ++가 아닌 libstdC++에서 발생하는 것으로 보입니다. 코드가 정확합니다. clang ++ 및 libC++를 사용하여 샘플 코드를 컴파일하면 helgrind (및 drd)는 어떤 종족에도 플래그를 지정하지 않습니다.

의 출력

:

g++ sample.cpp -pthread 

하고 :

clang++ sample.cpp -std=c++11 -stdlib=libstdc++ -pthread 

모두 helgrind에 따른 경주가되지만, 출력 :

clang++ sample.cpp -std=c++11 -stdlib=libc++ -pthread 

하지 않는 (즉, 사용 clang 자신의 표준 라이브러리)