6

我正在开发一个处理许多同步问题的多线程 C++ 程序。我正在使用 Visual Studio 2008。

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

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

欣赏回复。

4

2 回答 2

5

这篇关于多线程调试技术的文章对这个主题做了一些很好的总结:

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

...对于您的后一个具体问题,重要的是要了解 - 在大多数情况下 - 操作系统可以随时中断任何线程的执行,即使是那些“准备好”的线程执行。

于 2012-07-09T06:17:59.843 回答
2

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

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

因此,设计多线程应用程序非常重要,这样设计才能保证某些属性(例如,无死锁)。请注意,上一句中没有提到调试。它需要按设计工作,而不是通过寻找错误来工作。

有两个核心问题:

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

  2. 僵局。

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

使检查和正式证明某些属性(如免于死锁)变得更容易的设计示例之一是通信顺序进程 (CSP)

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

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

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

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

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

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

于 2012-07-09T16:04:08.167 回答