【问题标题】:How to prove that multithreading is working?如何证明多线程有效?
【发布时间】:2009-10-05 14:47:35
【问题描述】:

如何证明多线程在我的 C# 程序中有效?这是为了测试需求。例如,我将不得不向记录器类添加一些锁定(是的,我知道,我不应该编写自己的记录类),并且我需要一个测试用例来证明更改将起作用。

【问题讨论】:

  • 不确定您所说的“证明更改会起作用”是什么意思。你能证明的只有这么多——不要在你的单元测试中寻找解决停止问题的方法。
  • “证明”以说服我的队友。不试图显示 P==NP 或任何东西。

标签: c# multithreading testing


【解决方案1】:

如果您想测试您的锁定代码是否正确同步了对您的日志的访问,您需要构建保证争用的测试。这可能需要您重构代码,以便注入一个模拟日志编写器类,该类可以在任意时间段内保持日志的锁定。

这是一个宽泛的话题,你可以在 StackOverflow 上找到几个相关的问题,都值得一读:

CHESS 是一个正在开发的框架,用于识别“断言违规、死锁、活锁、数据争用和内存模型错误”。我实际上并没有使用过它,但它看起来可能非常有用。

【讨论】:

  • 你肯定想研究国际象棋。
【解决方案2】:

好吧,这听起来可能是错误的,但事实是您无法通过单元测试来证明多线程行为。话虽如此,您可以通过测试获得对代码的信心,随着时间的推移,它实际上可能会出现问题。

多线程代码是我在许多项目中存在的祸根。通常人们/开发人员不具备做好工作所需的专业知识。在任何人在野外看到它之前,错误通常会在很长一段时间内被忽视,然后您无法重现该问题以识别正在发生的事情。此外,尝试通过调试“修复”损坏的多线程代码通常不是可行的方法。

不管怎样,继续测试吧,做这么多并没有什么坏处,而且很容易做到。只需启动 N 个线程,让它们都等待 ManualRestEvent,然后在紧密循环中调用您的 api 几十万次 :)。 但首先我会建议您团队中的每个人都进行代码审查。遍历每一行代码,并考虑并行执行。问问自己:

  1. 我真的需要这个 lock() 吗?
  2. lock() 中必须包含的最少代码量是多少?
  3. 我可以使这个对象/状态不可变并避免锁定吗?
  4. 调用者有没有办法让代码在锁内执行?
  5. 查看所有在“volatile”锁内访问和更改的成员?
  6. 您是否正确使用 System.Threading.Thread.MemoryBarrier?
  7. 如果涉及多个锁,它们总是以相同的顺序获得吗?
  8. [维基在这里添加]

【讨论】:

  • +1,除了第一条语句之外,这是一个很好的建议。 :) 您可以在单元测试中证明有关多线程代码行为的具体事情(例如,您可以证明所有同步方法都遵守锁等)。你不能用单元测试来证明你的多线程代码是没有错误的——但这不是单元测试的目的。
【解决方案3】:

你不能 :) 这完全取决于时机,而且随时可能爆发。你必须在精神上检查每一种可能的情况,这是唯一的出路。这就是为什么很多开发人员认为多线程是不可能的。

【讨论】:

  • +1,几乎不可能测试所有可能的场景。如果您总是使用锁来同步对共享数据的访问,即使从性能角度来看它不是最佳解决方案,它也应该没问题。
  • 使用 CHESS 将允许您实际测试您的锁定是否正确 - 它使用每个可能的代码路径运行您的线程单元测试。在此处观看有关 CHESS 的视频:channel9.msdn.com/posts/Peli/…
【解决方案4】:

+1 给建议使用 Thread.Sleep() 的其他人

我实际上发现 Thread.Sleep() 对于模拟各种不同的竞态条件非常有用。但是,出于显而易见的原因,您需要确保在部署到生产之前删除(或使用配置禁用)Thread.Sleep。

在 Robert C Martin 的“清洁代码”一书中,他建议在单元测试中使用“抖动策略”来找出多线程问题。 “抖动”涉及在代码中添加随机等待时间,以便线程在不同时间以不同的顺序运行。然后,您可以多次运行单元测试,并且您的抖动可能会消除一些缺陷。重要的是不要仅仅因为它们在您下次运行测试时通过而忽略任何涉及多线程的单元测试失败。

咆哮:我不知道为什么有人会对建议使用 Thread.Sleep 的其他答案投反对票,但至少没有评论他们为什么投反对票。 p>

【讨论】:

    【解决方案5】:

    This post 对单元测试多线程应用程序进行了很好的讨论。

    【讨论】:

      【解决方案6】:

      实际上你做不到。但是,您可以编写一些写入控制台的调试时代码(例程开始、例程结束、例程执行的特殊操作……),这样您就可以看到例程同时运行。

      【讨论】:

        【解决方案7】:

        线程.睡眠。如果您在多线程中遇到竞争条件,那么放置得当的 Thread.Sleep 可以增加竞争条件的大小,使其更容易重现。

        WriteA();
        // potential race condition as another bit of code might read all the state
        // and only get A in their read.
        WriteB();
        

        WriteA();
        Thread.Sleep(60000);
        WriteB();
        

        然后您可以编写重现问题的代码。然后,您可以编写解决问题的代码。然后你可以断言你的修复工作。利润!

        【讨论】:

          【解决方案8】:

          另一个帖子发布了一个相关的答案,使用Microsoft's CHESS程序。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-24
            相关资源
            最近更新 更多