27

我帮助维护和构建一个相当大的 Swing GUI,有很多复杂的交互。我经常发现自己修复了由于代码中其他地方的某些竞争条件而导致事情进入奇怪状态的错误。

随着代码库变得越来越大,我发现通过文档指定哪些方法具有线程限制变得不太一致:最常见的是必须在 Swing EDT 上运行的方法。类似地,了解并提供静态感知(我们的自定义)侦听器在 EDT 上按规范通知是有用的。

所以我想到这应该是可以使用注释轻松执行的东西。瞧,至少存在一个静态分析工具CheckThread,它使用注释来完成此操作。它似乎允许您将方法声明为仅限于特定线程(最常见的是 EDT),并且会标记尝试调用该方法的方法,而无需同时声明自己仅限于该线程。

所以从表面上看,这似乎只是对源代码和构建周期的一种低痛苦、巨大的收益。我的问题是:

  • 对于使用 CheckThread 或类似库来强制执行线程约束的人,​​是否有任何成功案例?有失败的故事吗? 为什么成功/失败?
  • 这在理论上好吗? 有理论上的缺点吗?
  • 这在实践中好吗? 这值得么? 它传递了什么样的价值?
  • 如果它在实践中有效,有什么好的工具可以支持这一点? 我刚刚找到了 CheckThread,但承认我不完全确定我在寻找什么来寻找其他做同样事情的工具。

我知道这是否适合我们取决于我们的情况。但是我从来没有听说过有人在实践中使用过这样的东西,老实说,它似乎并没有从一些一般的浏览中占据太多。所以我想知道为什么。

4

3 回答 3

8

这个答案更侧重于您问题的理论方面。

从根本上讲,您是在断言:“此方法仅在某些线程下运行”。这个断言与您可能做出的任何其他断言并没有真正的不同(“该方法只接受小于 17 的整数作为参数 X”)。问题是

  • 这样的断言从何而来?
  • 静态分析仪可以检查它们吗?
  • 你从哪里得到这样一个静态分析器?

大多数此类断言必须来自软件设计师,因为他们是唯一知道意图的人。对此的传统术语是“契约式设计”,尽管大多数 DBC 方案只是在当前程序状态(C 的断言宏)并且它们应该真正超越程序的过去和未来状态(“时间断言”),例如,“这个例程将分配一个存储块,最终一些代码将释放它”。可以构建工具来尝试以随机方式确定断言是什么(例如,Engler 的断言归纳工作;其他人已经在该领域完成了工作)。这很有用,但误报是一个问题。实际上,要求设计人员编写此类断言的代码似乎并不特别繁重,并且确实是很好的长期文档。无论您是使用特定的“合同”语言结构还是使用if语句(“if Debug && Not () 然后 Fail();") 或将它们隐藏在注释中实际上只是方便的问题。当语言允许直接编写此类断言时,它很好。

静态检查此类断言是困难的。如果您只坚持当前状态,那么静态分析器几乎必须对整个应用程序进行完整的数据流分析,因为满足断言所需的信息可能来自应用程序的另一部分创建的数据。(在您的情况下,“EDT 内部”信号必须来自分析应用程序的整个调用图,以查看是否有任何调用路径导致来自不是 EDT 线程的线程的方法)。如果您使用时间属性,则静态检查几乎还需要某种状态空间验证逻辑;这些目前仍然是相当多的研究工具。即使使用了所有这些机器,静态分析仪在分析中通常也必须“保守”;如果他们可以

你从哪里得到这样的分析仪?鉴于所需的所有机器,它们很难制造,因此您应该期望它们很少见。如果有人建造了一个,那就太好了。如果不是...作为一般规则,您不希望自己从头开始执行此操作。最好的长期希望是有通用的程序分析机器来构建这样的分析器,以摊销构建所有基础设施的成本。(我构建了程序分析工具基础;请参阅我们的DMS 软件再工程工具包)。

使构建此类静态分析器“更容易”的一种方法是将它们处理的案例限制在较窄的范围内,例如 CheckThread。我希望 CheckThread 能够完全按照它目前所做的那样做,而且它不太可能变得更强大。

“断言”宏和其他此类动态“当前状态”检查流行的原因是它们实际上可以通过简单的运行时测试来实现。这很实用。这里的问题是您可能永远不会执行导致失败条件的路径。因此,对于动态分析,没有检测到故障并不是正确性的真正证据。感觉还是不错的。

底线:静态分析器和动态分析器各有长处。

于 2010-07-05T17:32:47.900 回答
3

我们还没有尝试过任何静态分析工具,但是我们使用 AspectJ 编写了一个简单的切面,它可以在运行时检测 java.awt 或 javax.swing 中的任何代码何时在 EDT 之外被调用。它在我们的代码中发现了几个缺少SwingUtilities.invokeLater(). 我们在整个 QA 周期中启用此方面,然后在发布前不久将其关闭。

于 2010-06-28T03:26:32.180 回答
2

根据要求,这与 Java 或 EDT 无关,但我已经看到 Coverity 的 C/C++ 并发静态分析检查器的良好结果。它们确实比不太复杂的检查器具有更高的误报率,但代码所有者似乎愿意忍受这一点,因为通过测试很难找到线程错误。恐怕细节是保密的,但 Dawson Engler 的公开论文(例如,“作为异常行为的错误”)非常适合“以下 «N» 个代码实例在执行 «X» 之前的一般方法Y»,; 这个实例没有。”</p>

于 2010-06-28T14:55:06.847 回答