首页 文章

boost :: thread应用程序,奇怪的数据竞争报告

提问于
浏览
4

我编写了一个boost :: thread应用程序,我可能会根据valgrind / helgrind报告获得一些竞争条件 . 我想确定这些比赛的原因 .

该计划是:

#include <boost/thread.hpp>

boost::mutex myMutex;
boost::condition_variable myConditionalVariable;
bool functionWasRun = false;

void function()
{
    {
        boost::lock_guard<boost::mutex> lock(myMutex);
        functionWasRun = true;
    }
    myConditionalVariable.notify_one();

    //doSomething1();
}

int main()
{
    boost::thread pThread(function);

    //Wait for the thread to start
    boost::unique_lock<boost::mutex> lock(myMutex);
    while (!functionWasRun)
        myConditionalVariable.wait(lock);

    //doSomething2();

    pThread.join();
}

对于这个简单的程序,valgrind / helgrind报告了以下错误:

== 10840 == Helgrind,一个线程错误检测器
== 10840 ==版权所有(C)2007-2013,以及OpenWorks LLP等人的GNU GPL .
== 10840 ==使用Valgrind-3.10.0.SVN和LibVEX;用-h重新运行版权信息
== 10840 ==命令:./ boost_network_test
== == 10840
== 10840 == ---主题公告--------------------------------------- ---
== == 10840
== 10840 ==线程#1是程序的根线程
== == 10840
== 10840 == ---主题公告--------------------------------------- ---
== == 10840
== 10840 ==线程#2已创建
== 10840 ==在0x6570EBE:克隆(clone.S:74)
== 10840 == by 0x4E44199:do_clone.constprop.3(createthread.c:75)
== 10840 == by 0x4E458BA:pthread_create @@ GLIBC_2.2.5(createthread.c:245)
== 10840 == by 0x4C30C90:??? (在/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so中)
== 10840 == by 0x547B3B8:boost :: thread :: start_thread_noexcept()(在/usr/lib/x86_64-linux-gnu/libboost_thread.so.1.54.0中)
== 10840 == by 0x53CFCC:boost :: thread :: start_thread()(thread.hpp:180)
== 10840 == by 0x53D31B:boost :: thread :: thread <void(&)()>(void(&)())(thread.hpp:267)
== 10840 == by 0x53CA7B:main(main_test.cpp:20)
== == 10840
== 10840 == --------------------------------------------- -------------------
== == 10840
== 10840 ==线程#1在0x8A21E0读取大小为8时可能发生数据竞争
== 10840 ==持有的锁:无
== 10840 ==在0x432CEB:boost :: mutex :: lock()(mutex.hpp:113)
== 10840 == by 0x43D197:boost :: unique_lock <boost :: mutex> :: lock()(lock_types.hpp:346)
== 10840 == by 0x43C1A0:boost :: unique_lock <boost :: mutex> :: unique_lock(boost :: mutex&)(lock_types.hpp:124)
== 10840 == by 0x53CA9E:main(main_test.cpp:23)
== == 10840
== 10840 ==这与线程#2的前一次写入大小为8冲突
== 10840 ==持有的锁:无
== 10840 ==在0x432CF6:boost :: mutex :: lock()(mutex.hpp:113)
== 10840 == by 0x43BFE9:boost :: lock_guard <boost :: mutex> :: lock_guard(boost :: mutex&)(lock_guard.hpp:38)
== 10840 == by 0x53C9DE:function()(main_test.cpp:10)
== 10840 == by 0x53DAAA:boost :: detail :: thread_data <void()()> :: run()(thread.hpp:117)
== 10840 == by 0x547BA49:??? (在/usr/lib/x86_64-linux-gnu/libboost_thread.so.1.54.0中)
== 10840 == by 0x4C30E26:??? (在/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so中)
== 10840 == by 0x4E45181:start_thread(pthread_create.c:312)
== 10840 == by 0x6570EFC:clone(clone.S:111)
== == 10840
== 10840 == --------------------------------------------- -------------------
== == 10840
== 10840 ==线程#1在0x8A21E0写入大小为8时可能发生数据竞争
== 10840 ==持有的锁:无
== 10840 ==在0x432CF6:boost :: mutex :: lock()(mutex.hpp:113)
== 10840 == by 0x43D197:boost :: unique_lock <boost :: mutex> :: lock()(lock_types.hpp:346)
== 10840 == by 0x43C1A0:boost :: unique_lock <boost :: mutex> :: unique_lock(boost :: mutex&)(lock_types.hpp:124)
== 10840 == by 0x53CA9E:main(main_test.cpp:23)
== == 10840
== 10840 ==这与线程#2的前一次写入大小为8冲突
== 10840 ==持有的锁:无
== 10840 ==在0x432CF6:boost :: mutex :: lock()(mutex.hpp:113)
== 10840 == by 0x43BFE9:boost :: lock_guard <boost :: mutex> :: lock_guard(boost :: mutex&)(lock_guard.hpp:38)
== 10840 == by 0x53C9DE:function()(main_test.cpp:10)
== 10840 == by 0x53DAAA:boost :: detail :: thread_data <void(
)()> :: run()(thread.hpp:117)
== 10840 == by 0x547BA49:??? (在/usr/lib/x86_64-linux-gnu/libboost_thread.so.1.54.0中)
== 10840 == by 0x4C30E26:??? (在/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so中)
== 10840 == by 0x4E45181:start_thread(pthread_create.c:312)
== 10840 == by 0x6570EFC:clone(clone.S:111)
== == 10840
== == 10840
== 10840 ==对于检测到的和抑制的错误计数,请重新运行:-v
== 10840 ==使用--history-level = approx或= none来提高速度,at
== 10840 ==冲突访问信息准确性降低的代价
== 10840 ==错误摘要:来自2个上下文的2个错误(被抑制:15个来自15个)

请问您能帮我确定如何修复此程序?

该程序在Ubuntu 14.04LTS,x86_64,gcc ver上运行 . 4.8.2,libboost v.1.54,valgrind 3.10.0 . 我的原始程序是一个使用ActiveObject类的复杂应用程序,它已经被剥离到最低限度看比赛条件模式 .

此线程可能与Debug boost::thread application, high false positive rate类似,但涉及条件变量/互斥锁 .

3 回答

  • 1

    正如有人说幕后发生了一些奇怪的事情,现在我找到了原因 .

    boost和POSIX变体中的代码都没有什么奇怪之处 . 要点是代码是在测试框架中使用 -fprofile-arcs 标志编译的,我将其用于代码覆盖(lcov) . 此标志正在检测程序并更改其行为 . 在我的情况下,程序中出现的任何对象(例如boost :: mutex)都会被检测,因此会干扰helgrind输出 . 当程序转换为POSIX线程时,所有对象都消失了 - 干扰也是如此,这就解释了为什么POSIX变体有效 .

    请尝试记住:HELGRIND = NO -fprofile-arcs FLAG

  • 3

    好消息是你的程序是正确的 . valgrind报告的所有比赛都是误报(尽管在加入线程之前考虑解锁互斥锁 - 以后可能会让你头疼) .

    我有OSX10.10所以必须从最新的trunk创建valgrind才能尝试这个 .

    这是它给我的东西(下面的截断输出)

    我用std :: thread / std :: mutex等重写了程序,并得到了类似的结果 .

    截断输出:

    ==79537== Helgrind, a thread error detector
    ==79537== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
    ==79537== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info
    ==79537== Command: Build/Products/Debug/cpprules
    ==79537== 
    --79537-- Build/Products/Debug/cpprules:
    --79537-- dSYM directory is missing; consider using --dsymutil=yes
    --79537-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option
    --79537-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times)
    --79537-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times)
    ==79537== ---Thread-Announcement------------------------------------------
    ==79537== 
    ==79537== Thread #2 was created
    ==79537==    at 0x10048D7EE: __bsdthread_create (in /usr/lib/system/libsystem_kernel.dylib)
    ==79537==    by 0x10003FC75: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000134E: main (in Build/Products/Debug/cpprules)
    ==79537== 
    ==79537== ---Thread-Announcement------------------------------------------
    ==79537== 
    ==79537== Thread #1 is the program's root thread
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 4 at 0x1005AA2D8 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x10058FFCF: spin_lock (in /usr/lib/system/libsystem_platform.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 4 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x10058FFDF: spin_unlock (in /usr/lib/system/libsystem_platform.dylib)
    ==79537==    by 0x10003FC75: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000134E: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x1005aa2d8 is in the Data segment of /usr/lib/system/libsystem_pthread.dylib
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 4 at 0x103DEB010 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A3293: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 4 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A30D8: pthread_create (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x10003FC75: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000134E: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x103deb010 is in a rw- mapped file segment
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during write of size 4 at 0x103DEB010 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A329B: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 4 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A30D8: pthread_create (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x10003FC75: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000134E: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x103deb010 is in a rw- mapped file segment
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during write of size 4 at 0x1005AA2D8 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x10058FFDF: spin_unlock (in /usr/lib/system/libsystem_platform.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 4 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x10058FFDF: spin_unlock (in /usr/lib/system/libsystem_platform.dylib)
    ==79537==    by 0x10003FC75: boost::thread::start_thread_noexcept() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000134E: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x1005aa2d8 is in the Data segment of /usr/lib/system/libsystem_pthread.dylib
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 4 at 0x10004D118 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x100048451: boost::thread_detail::enter_once_region(boost::once_flag&) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10003FA54: boost::detail::set_current_thread_data(boost::detail::thread_data_base*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10003FD6C: boost::(anonymous namespace)::thread_proxy(void*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 4 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x10004854A: boost::thread_detail::commit_once_region(boost::once_flag&) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10003F9F4: boost::detail::get_current_thread_data() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000139F: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x10004d118 is in the Data segment of /usr/local/lib/libboost_thread.dylib
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 8 at 0x10004D120 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x10003FA78: boost::detail::set_current_thread_data(boost::detail::thread_data_base*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10003FD6C: boost::(anonymous namespace)::thread_proxy(void*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 8 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A1618: pthread_key_create (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x10003F9E8: boost::detail::get_current_thread_data() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000139F: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x10004d120 is in the Data segment of /usr/local/lib/libboost_thread.dylib
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 8 at 0x1005AC448 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A269E: pthread_setspecific (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 8 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A1614: pthread_key_create (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x10003F9E8: boost::detail::get_current_thread_data() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000139F: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x1005ac448 is in the Data segment of /usr/lib/system/libsystem_pthread.dylib
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during write of size 1 at 0x100009D48 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x100000F49: function() (in Build/Products/Debug/cpprules)
    ==79537==    by 0x10003FD79: boost::(anonymous namespace)::thread_proxy(void*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous read of size 1 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x10000138D: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x100009d48 is in the Data segment of Build/Products/Debug/cpprules
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during write of size 8 at 0x100009D28 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A4099: _pthread_cond_updateval (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A294D: _pthread_cond_signal (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x100000F77: function() (in Build/Products/Debug/cpprules)
    ==79537==    by 0x10003FD79: boost::(anonymous namespace)::thread_proxy(void*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 8 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A3DE1: _pthread_cond_wait (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1000014AA: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x100009d28 is in the Data segment of Build/Products/Debug/cpprules
    ==79537== 
    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during read of size 8 at 0x1005AC448 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A4791: _pthread_tsd_cleanup (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A44E4: _pthread_exit (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3306: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537== 
    ==79537== This conflicts with a previous write of size 8 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A1614: pthread_key_create (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x10003F9E8: boost::detail::get_current_thread_data() (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x10000139F: main (in Build/Products/Debug/cpprules)
    ==79537==  Address 0x1005ac448 is in the Data segment of /usr/lib/system/libsystem_pthread.dylib
    ==79537==
    

    ...

    ==79537== ----------------------------------------------------------------
    ==79537== 
    ==79537== Possible data race during write of size 8 at 0x100009C98 by thread #1
    ==79537== Locks held: none
    ==79537==    at 0x1005A37DD: pthread_mutex_destroy (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x100005D50: boost::mutex::~mutex() (in Build/Products/Debug/cpprules)
    ==79537==    by 0x1003A38EC: __cxa_finalize_ranges (in /usr/lib/system/libsystem_c.dylib)
    ==79537==    by 0x1003A3BEF: exit (in /usr/lib/system/libsystem_c.dylib)
    ==79537==    by 0x1002F05CF: start (in /usr/lib/system/libdyld.dylib)
    ==79537== 
    ==79537== This conflicts with a previous read of size 8 by thread #2
    ==79537== Locks held: none
    ==79537==    at 0x1005A1655: _pthread_mutex_lock (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x100000EBB: function() (in Build/Products/Debug/cpprules)
    ==79537==    by 0x10003FD79: boost::(anonymous namespace)::thread_proxy(void*) (in /usr/local/lib/libboost_thread.dylib)
    ==79537==    by 0x1005A32FB: _pthread_body (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A3278: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==    by 0x1005A14B0: thread_start (in /usr/lib/system/libsystem_pthread.dylib)
    ==79537==  Address 0x100009c98 is in the Data segment of Build/Products/Debug/cpprules
    ==79537== 
    ==79537== 
    ==79537== For counts of detected and suppressed errors, rerun with: -v
    ==79537== Use --history-level=approx or =none to gain increased speed, at
    ==79537== the cost of reduced accuracy of conflicting-access information
    ==79537== ERROR SUMMARY: 34 errors from 33 contexts (suppressed: 0 from 0)
    
  • -2

    这可能是 myConditionalVariable 上的竞争条件吗?

    如果是这样,下面将解决问题 .

    void function()
    {
        {
            boost::lock_guard<boost::mutex> lock(myMutex);
            functionWasRun = true;
            myConditionalVariable.notify_one();
        }
    
        //doSomething1();
    }
    
    int main()
    {
        boost::thread pThread(function);
    
        //Wait for the thread to start
        while (!functionWasRun)
        {
            boost::unique_lock<boost::mutex> lock(myMutex);
            myConditionalVariable.wait(lock);
        }
    
        //doSomething2();
    
        pThread.join();
    }
    

相关问题