阅读对此答案的评论,特别是:
仅仅因为您不能编写测试并不意味着它没有坏。未定义的行为通常会按预期方式起作用(C和C ++充满了),竞争条件,由于内存模型弱而可能重新排序... – CodesInChaos 7小时前
如果无法复制@CodesInChaos,则也无法测试写入“修复”的代码。在我看来,将未经测试的代码付诸实践是更糟糕的罪行– RhysW 5小时前
...让我想知道是否有任何好的通用方法来持续触发由测试用例中的竞争条件引起的生产问题中很少发生的问题。
阅读对此答案的评论,特别是:
仅仅因为您不能编写测试并不意味着它没有坏。未定义的行为通常会按预期方式起作用(C和C ++充满了),竞争条件,由于内存模型弱而可能重新排序... – CodesInChaos 7小时前
如果无法复制@CodesInChaos,则也无法测试写入“修复”的代码。在我看来,将未经测试的代码付诸实践是更糟糕的罪行– RhysW 5小时前
...让我想知道是否有任何好的通用方法来持续触发由测试用例中的竞争条件引起的生产问题中很少发生的问题。
Answers:
自1978年左右开始从事这项疯狂的业务后,几乎所有时间都花在嵌入式实时计算,工作多任务,多线程,多系统,有时有多个物理处理器的工作上,这比我所追求的目标还多在这种情况下,我认为您的问题的答案很简单。
没有。
在测试中没有很好的通用方法来触发竞争条件。
您唯一的希望是完全在系统之外进行设计。
如果发现某人塞入其中,则应该将他放到蚁丘外面,然后重新设计以消除它。在系统之外设计了他的人造狗(发音为f *** up)之后,就可以将其从蚂蚁身上释放出来。(如果蚂蚁已经吃掉了他的骨头,只剩下骨头,则张贴一个标语,上面写着“这是将种族条件放入XYZ项目的人会发生的事情!”,然后离开那里。)
对于这类问题,我所知道的最好的工具是Valgrind的扩展名Helgrind。
基本上,Valgrind会模拟一个虚拟处理器,并在其之上运行您的二进制文件(未修改),因此它可以检查对内存的每一次访问。使用该框架,Helgrind监视系统调用以推断何时互斥机制未正确保护对共享变量的访问。这样,即使它实际上没有发生,它也可以检测到理论上的竞争情况。
英特尔出售一种非常相似的工具,称为“ 英特尔检查器”。
这些工具可以提供很好的结果,但是您的程序在分析过程中会变慢。
暴露多线程错误需要强制执行的不同线程以特定的交错顺序执行其步骤。通常,如果没有手动调试或操纵代码来获得某种“句柄”来控制这种交错,就很难做到这一点。但是更改行为异常的代码通常会影响这种不可预测性,因此很难实现自动化。
Jaroslav Tulach在《实用API设计》中描述了一个不错的技巧:如果所讨论的代码中包含日志记录语句,请操纵这些日志记录语句的使用者(例如,注入的伪终端),以便它接受特定日志中的各个日志消息。根据其内容排序。这使您可以控制不同线程中步骤的交织,而不必向生产代码中添加尚不存在的任何内容。
无法绝对确定不存在各种未定义的行为(特别是种族条件)。
但是,有许多工具可以显示大量此类情况。即使您不能证明您的修复程序有效,您也可以证明此类工具当前存在问题。
一些用于此目的的有趣工具:
Valgrind是一个内存检查器。它查找内存泄漏,读取未初始化的内存,使用悬空指针和越界访问。
Helgrind是线程安全检查器。它找到比赛条件。
两者都通过动态检测工作,即它们将您的程序保持原样并在虚拟化环境中执行。这使它们不打扰,但速度很慢。
UBSan是未定义的行为检查器。它会发现C和C ++未定义行为的各种情况,例如整数溢出,超出范围的移位和类似的内容。
MSan是内存检查器。它的目标与Valgrind相似。
TSan是线程安全检查器。它的目标与Helgrind相似。
这三个内置在Clang编译器中,并在编译时生成代码。这意味着您需要将它们集成到构建过程中(特别是必须使用Clang进行编译),这使得它们的初始设置比* grind困难得多,但另一方面,它们的运行时开销却要低得多。
我列出的所有工具都可以在Linux上使用,其中一些可以在MacOS上使用。我认为Windows上尚无可靠的工作。
似乎大多数答案将这个问题误解为“我如何自动检测比赛条件?” 当问题确实是“找到测试条件时,如何在测试中重现竞赛条件”?
这样做的方法是在仅用于测试的代码中引入同步。例如,如果在事件A和事件B之间发生事件X时发生了竞争情况,则为了测试您的应用程序,编写一些代码,等待事件A发生后事件X发生。您可能需要某种测试方法来与您的应用程序对话以告知它(“嘿,我正在测试此东西,因此请在此位置等待此事件”)。
我正在使用node.js和mongo,其中一些操作涉及在多个集合中创建一致的数据。在这些情况下,我的单元测试将调用应用程序以告知它“设置等待事件X”,一旦应用程序将其设置好,事件X的测试将运行,测试随后将告知应用程序(“我已经完成了等待事件X”),因此其余测试将正常运行。
这里的答案在python上下文中详细解释了这种类型的事情:https : //stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this-python-code-可靠地