2011-12-06 31 views
11

Khi tôi chuyển mã của tôi sang C++ 11, tôi rất muốn chuyển mã pthread thành std :: thread. Tuy nhiên, tôi dường như nhận được điều kiện cuộc đua sai trên các chương trình rất đơn giản trong drd và trong helgrind.Trạng thái hiện tại của drd và helgrind hỗ trợ cho std :: thread

#include <thread> 

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

Đoạn trích đầu ra Helgrind - Tôi cũng gặp lỗi tương tự trong drd, sử dụng gcc 4.6.1, valgrind 3.7.0 trên Ubuntu 11.11 amd64.

Câu hỏi của tôi là: kiểm tra

  • sự tỉnh táo: Tôi có làm điều gì sai trái? Những người khác nhận được báo cáo sai tương tự về chương trình std :: thread đơn giản?
  • Người dùng hiện tại của std :: thread sử dụng để phát hiện điều kiện chủng tộc là gì?

Tôi không muốn chuyển một tấn mã từ pthread sang std::thread cho đến khi một số công cụ quan trọng như helgrind/drd đã bắt kịp.

==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== 

Trả lời

12

std :: thread sử dụng con trỏ được chia sẻ nội bộ. Những gì bạn đang thấy là dương tính giả trên số tham chiếu của đối tượng chia sẻ con trỏ đó. Bạn có thể tránh những sự tích cực sai này bằng cách thêm bốn dòng mã được hiển thị bên dưới vào mỗi tệp nguồn ngay trước tiêu đề C++ bao gồm các chỉ thị. Lưu ý: điều này chỉ hoạt động với phiên bản libstdC++ đi kèm với gcc 4.6.0 trở lên.

#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 

Để biết thêm thông tin, hãy xem phần Săn bắn dữ liệu trong hướng dẫn sử dụng libstdC++ (http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html).

+0

+1 mẹo tuyệt vời! Tôi chắc chắn sẽ thử nó - thx. – kfmfe04

+2

Lưu ý: chỉ phát hiện ra rằng có lỗi trong libstdC++ không cho phép std :: thread được chú thích đúng cách - xem thêm [gcc bug 51504] (http://gcc.gnu.org/bugzilla/show_bug.cgi ? id = 51504). – user251384

3

Rất có thể những gì bạn thấy là dương tính giả. Tôi đang quan sát một hành vi tương tự trong mã của tôi.

Cụ thể, các cảnh báo có vẻ liên quan đến việc triển khai lớp con trỏ chia sẻ, và sự hiểu biết của tôi là trên nền tảng của bạn (mà tôi đoán là x86/x86-64?) GCC đang sử dụng hướng dẫn lắp ráp nguyên tử tối ưu trong con trỏ dùng chung máy đếm tham chiếu. Vấn đề là valgrind có thể phát hiện lỗi khi sử dụng các nguyên tố POSIX (khóa, mutexes, etx.), Nhưng nó không thể đối phó với các nguyên thủy cấp thấp hơn.

Những gì tôi đã làm cho đến nay là chỉ cần lọc ra khỏi đầu ra của valgrind các cảnh báo (có thể bạn có thể viết một số tệp đàn áp thực hiện công việc theo cách thích hợp).

+0

thx để kiểm tra sự lành mạnh - Tôi đã chuyển thành pthreads thành std :: thread. Ngoại trừ phạm vi std :: conditional_variable một cách chính xác, hầu hết các porting là không đau (không đáng ngạc nhiên, vì pthreads trong không quá xa bên dưới). Tôi sẽ giải quyết một số lỗi drd/helgrind với các lệnh cấm trong một hoặc hai ngày tiếp theo và thêm chúng vào OP. – kfmfe04

1

Nếu bạn sử dụng tăng, bạn có thể bật sử dụng các phần tử gốc thay vì các phép toán nguyên tử cho các con trỏ được chia sẻ. Sau đó bạn có thể sử dụng một phiên bản của mã của bạn được biên dịch với BOOST_SP_USE_PTHREADS để phân tích helgrind, và bạn sẽ không nhận được các lỗi vì helgrind hiểu các pthreads nguyên thủy.

Xem http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety để biết thêm thông tin.

Các vấn đề liên quan