代码之家  ›  专栏  ›  技术社区  ›  MicSim

如何检测和调试多线程问题?

  •  76
  • MicSim  · 技术社区  · 16 年前

    这是对 this question 在这一点上,我没有得到任何意见。以下是一个简短的问题:

    是否有可能检测和调试来自多线程代码的问题?

    我想知道是否有任何特殊的日志框架、调试技术、代码检查器或其他任何东西来帮助解决这些问题。欢迎采用一般方法。如果任何答案与语言有关,请保持不变。NET和Java。

    17 回复  |  直到 8 年前
        1
  •  90
  •   L. Cornelius Dol    5 年前

    线程/并发问题 众所周知,它们很难复制,这也是你应该设计以避免或至少最小化概率的原因之一。这就是不可变对象如此有价值的原因。尝试将可变对象隔离到单个线程,然后仔细控制线程之间可变对象的交换。尝试使用对象移交的设计进行编程,而不是“共享”对象。对于后者,使用完全同步的控制对象(这更容易推理),并避免让同步对象利用其他必须同步的对象,也就是说,尽量保持它们的自包含性。你最好的防御是一个好的设计。

    往往极难复制,甚至更难从手动代码审查中识别。有了这些,除了进行广泛的测试以进行复制外,我通常采取的方法是对可能性进行推理,并尝试记录信息以证明或反驳理论。如果你有国家腐败的直接证据,你可能会根据腐败来推断可能的原因。

    此外,请注意可能的行为差异,这些差异取决于CPU内核、管道、总线带宽等的数量。硬件的更改会影响您复制问题的能力。有些问题只会出现在单核CPU上,其他问题只会在多核CPU上出现。

    java.util.concurrent 是你的朋友。 编写自己的并发控制对象既困难又充满危险;如果你有选择的话,就交给专家吧。

        2
  •  7
  •   Community CDub    8 年前

    我以为 answer other question

    此外,一些分析工具可以检测到一些潜在的问题。例如, FindBugs

    vanslly 在对此答案的评论中指出,研究位置良好的测井输出也很有帮助,但要注意 Heisenbugs .

        3
  •  6
  •   bLaXjack    6 年前

    javapathfinder
    它与Eclipse和Netbean IDE都能很好地配合使用。

    https://github.com/javapathfinder

        4
  •  5
  •   krosenvold    16 年前

    假设我有难以重现的问题报告,我总是通过阅读代码来发现这些问题,最好是成对代码阅读,这样你就可以讨论线程语义/锁定需求。当我们基于 报告的问题

    很抱歉不能告诉你按ctrl+shift+f13,但我认为没有这样的东西可用。但只要想想 通常在代码中给出相当强烈的方向感,所以你不必从main()开始。

        5
  •  5
  •   mghie    16 年前

    除了您已经得到的其他好答案外:始终在具有至少与客户使用的处理器/处理器内核数量相同的机器上进行测试,或者在您的程序中有活动线程的情况下进行测试。否则,一些多线程错误可能很难重现。

        6
  •  5
  •   ChrisW    16 年前

    有时你可以在日志文件中看到问题:“这个线程在这里检测到非法/意外状态……看,另一个线程在这之前和/或之后都在这样做。”

        7
  •  3
  •   Peter Huber    11 年前

    1. 不增加任何延迟
    2. 不使用任何锁
    3. 多线程安全

    public const int MaxMessages = 0x100;
    string[] messages = new string[MaxMessages];
    int messagesIndex = -1;
    
    public void Trace(string message) {
      int thisIndex = Interlocked.Increment(ref messagesIndex);
      messages[thisIndex] = message;
    }
    

    Trace()方法是多线程安全的、非阻塞的,可以从任何线程调用。在我的PC上,执行大约需要2微秒,这应该足够快了。

    在您认为可能出错的地方添加Trace()指令,让程序运行,等待错误发生,停止跟踪,然后调查跟踪是否有任何错误。

    关于这种方法的更详细描述,它还收集线程和定时信息,回收缓冲区并很好地输出跟踪,您可以在以下网址找到: CodeProject:实时调试多线程代码 1

        8
  •  2
  •   Mouze    10 年前

    一个小图表,其中包含调试多线程代码时需要记住的一些调试技术。 (更新文件位于 this link )

    Multithreaded debugging chart

        9
  •  1
  •   Brian Rasmussen    16 年前

    Visual Studio允许您检查每个线程的调用堆栈,并且可以在它们之间进行切换。仅仅跟踪各种线程问题是远远不够的,但这是一个开始。计划在即将到来的VS2010中对多线程调试进行大量改进。

    我曾使用Winge+SoS解决中的线程问题。NET代码。您可以检查锁(同步块)、线程调用堆栈等。

        10
  •  1
  •   Sean    16 年前

    Tess Ferrandez's blog 有很好的例子说明如何使用Winchester调试中的死锁。网。

        11
  •  1
  •   zvrba    16 年前

        12
  •  1
  •   Thomas Krieger    11 年前
        13
  •  0
  •   Community CDub    8 年前

    the way that Princess recommended for your other question (不可变对象和Erlang风格的消息传递)。检测多线程问题将更容易,因为线程之间的交互将被很好地定义。

        14
  •  0
  •   Kuldeep Tiwari    12 年前

    根据我的经验,我可以说最难的部分是认识到这是一个线程问题,最好的解决方案是仔细审查多线程代码。只要仔细查看线程代码,你就应该试着找出可能出错的地方。其他方式(线程转储、分析器等)将排在第二位。

        15
  •  0
  •   John Smith jjcaicedo    6 年前

    缩小被调用的函数范围,排除可能和不可能的原因。当你发现你怀疑可能导致问题的代码段时,给它添加大量详细的日志记录/跟踪。一旦问题再次发生,检查日志,看看代码的执行方式与“基线”情况下的不同。

    https://learn.microsoft.com/en-us/visualstudio/debugger/using-the-parallel-stacks-window?view=vs-2019

    https://learn.microsoft.com/en-us/visualstudio/debugger/walkthrough-debugging-a-parallel-application?view=vs-2019

        16
  •  -2
  •   BNR    8 年前

    我使用GNU并使用简单的脚本

    b func.cpp:2871
    r
    #c
    while (1)
    next
    #step
    end
    
        17
  •  -10
  •   max    16 年前

    大的 多线程应用程序。