找到竞争条件的方法

时间:2010-06-28 18:36:49

标签: c++ visual-studio-2008 conditional-statements race-condition

我有一些带有竞争条件的代码......我知道这是一种竞争条件,因为它不会一直发生,而且似乎更常发生在双核机器上。

当我追踪时,它永远不会发生。虽然,它也可能是一个僵局。通过分析完成和不发生的日志的完成阶段,我已经能够将此错误指向单个函数。但是,我不知道在这个功能的范围内发生了什么。它不在顶层。

如果是竞争条件,添加日志语句或断点将会改变时间,并防止这种情况发生。

除了获得竞争条件分析器之外,我还能使用哪种技术来确定这种情况发生在哪里?

这是在Visual Studio 9中,使用C ++(非管理类型)。

8 个答案:

答案 0 :(得分:6)

CLang和gcc 4.8+中包含一个名为ThreadSanitizer的工具。

使用-fsanitize=thread标志

编译代码

示例:

$ cat simple_race.cc
#include <pthread.h>
#include <stdio.h>

int Global;

void *Thread1(void *x) {
  Global++;
  return NULL;
}

void *Thread2(void *x) {
  Global--;
  return NULL;
}

int main() {
  pthread_t t[2];
  pthread_create(&t[0], NULL, Thread1, NULL);
  pthread_create(&t[1], NULL, Thread2, NULL);
  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);
}

输出

$ clang++ simple_race.cc -fsanitize=thread -fPIE -pie -g
$ ./a.out 
==================
WARNING: ThreadSanitizer: data race (pid=26327)
  Write of size 4 at 0x7f89554701d0 by thread T1:
    #0 Thread1(void*) simple_race.cc:8 (exe+0x000000006e66)

  Previous write of size 4 at 0x7f89554701d0 by thread T2:
    #0 Thread2(void*) simple_race.cc:13 (exe+0x000000006ed6)

  Thread T1 (tid=26328, running) created at:
    #0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
    #1 main simple_race.cc:19 (exe+0x000000006f39)

  Thread T2 (tid=26329, running) created at:
    #0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
    #1 main simple_race.cc:20 (exe+0x000000006f63)
==================
ThreadSanitizer: reported 1 warnings

答案 1 :(得分:5)

将睡眠放在代码的各个部分。即使它(或异步代码)睡了几秒钟,线程安全的东西也是线程安全的。

答案 2 :(得分:2)

确实有一些尝试自动找到竞争条件。

我与种族条件检测一起阅读的另一个术语是RaceFuzzer,但我无法找到有关它的真正有用的信息。

我认为这是一个相对较高的调查领域,因此据我所知 - 主要是关于这一主题的理论论文。但是,尝试用谷歌搜索上面的关键字,也许你会找到一些有用的信息。

答案 3 :(得分:2)

我知道跟踪这些内容的最佳方法是在Visual Studio中使用CHESS。这不是一个简单的工具,可能需要逐步测试您的应用程序的子部分。祝你好运。

答案 4 :(得分:2)

我有幸使用Visual Studio的跟踪点来查找竞争条件。当然它仍会影响时间,但在我使用它的情况下,至少,它还不足以完全防止竞争条件的发生。它至少比专用日志记录更具破坏性。

除此之外,尝试发布代码,允许其他人查看它。只是详细研究代码并不是查找竞争条件的坏方法。

答案 5 :(得分:2)

所以,我的大锤方法如下,需要很大的耐心,并且在最好的情况下可以让你走上正轨。我用它来弄清楚这个特殊问题是怎么回事。 我一直在使用跟踪点,一个在可疑的高级功能的开头,一个在最后。将跟踪点向下移动。如果在函数开头添加跟踪点导致您的错误停止发生,请将跟踪点向下移动,直到您可以再次重现该条件。我们的想法是,如果你在最终触发不安全代码的调用之后放置它,那么跟踪点不会影响时序,但如果你之前放置它,它将会影响。另外,请注意您的输出窗口。你的错误发生在什么消息之间?您也可以使用跟踪点来缩小此范围。

一旦将您的错误缩小到可管理的代码区域,您就可以抛出断点并查看其他线程在此处的用途。

答案 6 :(得分:1)

它也可以是一种不受保护的资源,可以解释不一致的行为(特别是如果在单个核心上它工作正常而不是双核心)。在任何情况下,代码审查(对于竞争条件和非线程安全的源代码)都可以是解决方案的最短路径。

答案 7 :(得分:0)

您可以使用Intel Inspector之类的工具来检查某些类型的竞争条件。