调试是否会改变多线程C ++程序的行为?

时间:2012-07-09 06:08:54

标签: c++ multithreading debugging visual-studio-2008 asynchronous

我正在研究一个处理大量同步问题的多线程C ++程序。我正在使用Visual Studio 2008。

当我使用断点调试程序时,我的程序的运行时行为(跨线程执行语句的顺序)似乎发生了变化。这可以解释一下吗?这里的概念是什么?我希望执行的顺序保持不变。

第二个问题 - 如果Thread1被等待函数调用阻止。 Thread2具有等待执行的语句,处于就绪状态。是否存在程序等待Thread1继续而不是执行Thread2的情况?我已经删除了两个线程之间的所有依赖关系,并确保Thread2不等待任何资源。

感谢回复。

2 个答案:

答案 0 :(得分:5)

This article on multithreaded debugging techniques就该主题提出了一些很好的总结点:

  

在调试器下运行时,多线程错误可能不会浮出水面。多线程错误对应用程序中事件的时间非常敏感。在调试器下运行应用程序会改变时序,因此可能会掩盖问题。如果您的应用程序在测试中失败,或者更糟糕的是客户环境,但在调试器下可靠运行,则几乎肯定是代码中的计时问题。

...还有更多针对您特定的后一个问题,重要的是要了解 - 在大多数情况下 - 操作系统可以随时中断任何线程的执行,即使是“准备“执行。

答案 1 :(得分:2)

请记住:没有办法正常调试多线程应用程序,就像调试它“直到它工作”。

你需要有一种方式以某种方式向自己证明不存在死锁,并且所有数据访问都是在需要的地方进行序列化。这很难做到,即使是经验丰富的开发人员也可能会错过某些案例。

因此,设计多线程应用程序非常重要,以便设计保证某些属性(例如 - 免于死锁)。请注意,上一句中的任何地方都没有提到调试。它需要按设计工作,而不是误操作。

有两个核心问题:

  1. 序列化对数据结构的访问。

  2. 死锁。

  3. 我在下面讨论的事件驱动或CSP方法会自动处理#1。僵局问题并非微不足道,仍然是一个活跃的研究课题。即,证明缺乏僵局的方法(以及为它设计的方法!)。

    设计的一个示例是communicating sequential processes (CSP)

    ,它可以更容易地检查并正式证明某些属性,例如免于死锁。

    CSP方法在大多数应用程序开发框架中都可用,并且可以作为无共享事件驱动系统实现。核心功能是:

    • 线程通过彼此之间发送事件(消息)进行通信。

    • 数据结构永远不会在线程之间直接共享,而是事件拥有数据。

    • 唯一的同步是在发布事件时按顺序访问事件队列。

    只要更高级别的抽象不使用事件传递来重新实现容易出现死锁的抽象,这本身就可以确保不受死锁的影响。例如,即使事件传递,也可以获得用餐哲学家问题的死锁,但现在您通过事件(消息)显式传递有关资源的信息。因此,问题至少是明确的,你不得不考虑它。可以这么说,问题并没有在地毯下扫过。

    Formal techniques 证明不会发生死锁/活锁可以更容易地应用于实现CSP的事件传递生产代码。事件接受代码可以提供运行时内省,允许为每个状态提取已接受事件集,以及状态集(在内部它是状态机)。此信息通常足以证明不存在死锁的可能性,或者可以枚举一小组死锁方案,然后可以以其他方式处理。毕竟,CSP形式主义通常不能捕获软件的完整语义,因此语义本身可用于进一步表明不会发生死锁,或者以其他方式处理死锁。