调试 boost::thread 应用,误报率高

Posted

技术标签:

【中文标题】调试 boost::thread 应用,误报率高【英文标题】:Debug boost::thread application, high false positive rate 【发布时间】:2011-12-21 09:52:24 【问题描述】:

我编写了一个 boost::thread 应用程序,我可能会遇到一些竞争条件。我想调试这个程序。因此我使用了以下 valgrind 工具:

    halgrind drd

不幸的是,他们的误报率很高。因此,valgrind --tool=drd 下面的非常简单的程序抱怨 94 错误,不应该是。因此,对于我的复杂程序,我得到了大约 15000 个错误。所以真的很难找到真正的错误。

我可以使用以下 boost 库 1.46.0 和 1.47.0 重现此行为。并且使用 valgrind 3.7.0 SVN 和 valgrind 3.8.0 SVN。我试用的操作系统是 Ubuntu 11.10 和 Mac OS X 10.7。 gcc 4.2.1和gcc 4.6.1所在的编译器。

#include <iostream>
#include <boost/thread.hpp>

void run()

    //do some stuff here


int main(int argc, char* argv[])

    boost::thread thread(run);
    thread.join();
    std::cerr << "main: done" << std::endl;
    return 0;

;

你如何调试你的 boost 线程程序?还有其他更适合的工具吗?

解决方案

3.6.1版本之后的valgrind好像坏了。如果我使用 valgrind 3.6.1 一切正常。

这里是来自valgrind --tool=drd的错误报告:

==60767== Thread 1:
==60767== Conflicting store by thread 1 at 0x100026ec0 size 8
==60767==    at 0x2A316E: pthread_mutex_lock (in /usr/lib/system/libsystem_c.dylib)
==60767==    by 0x2A82FA: _pthread_cond_wait (in /usr/lib/system/libsystem_c.dylib)
==60767==    by 0x32A4E: boost::condition_variable::wait(boost::unique_lock<boost::mutex>&) (in /usr/local/lib/libboost_thread.dylib)
==60767==    by 0x2BE5A: boost::thread::join() (in /usr/local/lib/libboost_thread.dylib)
==60767==    by 0x10000195C: main (in ./playgroudThreads)
==60767== Address 0x100026ec0 is at offset 144 from 0x100026e30. Allocation context:
==60767==    at 0xC5B3: malloc (vg_replace_malloc.c:266)
==60767==    by 0x9968D: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==60767==    by 0x1000069ED: boost::detail::thread_data<void (*)()>* boost::detail::heap_new_impl<boost::detail::thread_data<void (*)()>, void (*&)()>(void (*&)()) (in ./playgroudThreads)
==60767==    by 0x100006A87: boost::detail::thread_data<void (*)()>* boost::detail::heap_new<boost::detail::thread_data<void (*)()>, void (*)()>(void (*&)()) (in ./playgroudThreads)
==60767==    by 0x100006ACA: boost::shared_ptr<boost::detail::thread_data_base> boost::thread::make_thread_info<void (*)()>(void (*)()) (in ./playgroudThreads)
==60767==    by 0x100006B08: boost::thread::thread<void (*)()>(void (*)(), boost::disable_if<boost::is_convertible<void (*&)(), boost::detail::thread_move_t<void (*)()> >, boost::thread::dummy*>::type) (in ./playgroudThreads)
==60767==    by 0x100001950: main (in ./playgroudThreads)
==60767== Other segment start (thread 2)
==60767==    at 0x2A7B68: thread_start (in /usr/lib/system/libsystem_c.dylib)
==60767== Other segment end (thread 2)
==60767==    at 0x3E667A: mach_msg_trap (in /usr/lib/system/libsystem_kernel.dylib)
==60767==    by 0x3DED38: semaphore_create (in /usr/lib/system/libsystem_kernel.dylib)
==60767==    by 0x2A50F7: new_sem_from_pool (in /usr/lib/system/libsystem_c.dylib)
==60767==    by 0x2A6199: _pthread_exit (in /usr/lib/system/libsystem_c.dylib)
==60767==    by 0x2A48C9: _pthread_start (in /usr/lib/system/libsystem_c.dylib)
==60767==    by 0x2A7B74: thread_start (in /usr/lib/system/libsystem_c.dylib)

【问题讨论】:

gdb 的问题是我的应用程序只是很少崩溃。所以用gdb很难捕捉到崩溃的程序。 确实,不规则的崩溃非常令人沮丧且难以调试。使用 kdbg,一个 GUI 调试器,这样可能更容易发现错误。 问题是错误很可能是竞争条件。使用 gdb 或 kdbg 检测竞态条件非常困难。因为它通常不会崩溃并且工作正常。 可以使用信号量来防止这种情况。当然这使得程序依赖于操作系统:) 我对需要从多个线程访问的所有变量都有一个互斥锁。所以它应该是线程安全的。但它看起来很轻,我忽略了一些东西。我多次查看我的代码并没有弄清楚是什么,因此我想要一个调试器来找出我在哪里有竞争条件。 【参考方案1】:

来自DRD manual

happens-before 数据竞争检测器的一个重要优势是它们不会报告任何误报。 DRD 基于happens-before 算法。

因此,如果实现仅使用 POSIX 线程而不是 Linux 的 futex 等非 POSIX 的东西,那么 DRD 不会有任何误报。

因此,如果 DRD 报告了误报,那么在像您这样的无种族程序上,它就有一个错误。它不应该有误报。

但是,我无法在我的机器上重现您报告的错误(Archlinux/ gcc 4.6.2 / valgrind 3.6.1 / boost 1.47)。

【讨论】:

你自己编译过boost和valgrind吗? @tune2fs 不,ArchLinux 正在滚动发布。这意味着它拥有一切的最新稳定版本。 用 Ubuntu 10.04、valgrind 3.6.0 和 gcc 4.4.3 再次检查,再次没有错误。你确定你没有为 valgrind 使用 -v 选项吗? 自从我使用 valgrind 3.6.1 之后就没有错误了。从 SVN 构建的最新 valgrind 版本会出现这些错误。

以上是关于调试 boost::thread 应用,误报率高的主要内容,如果未能解决你的问题,请参考以下文章

如何计算分层 K 折交叉验证的不平衡数据集的误报率?

机器学习准确率精确率召回率误报率漏报率概念及公式

如何在相当平衡的二元分类中解决非常高的误报率?

金融企业做AIOps,如何解决运维监控误报率高和时效性延迟?

Boost.Thread 线程在发布版本中未在 iPhone/iPad 上启动

gdb 调试多线程