记住:没有办法正常调试多线程应用程序,就像调试它“直到它工作”一样。
您需要以某种方式向自己证明不会出现死锁,并且所有数据访问都在需要的地方进行了序列化。这很难做到,即使是经验丰富的开发人员也可能会错过某些情况。
因此,设计多线程应用程序非常重要,这样设计才能保证某些属性(例如,无死锁)。请注意,上一句中没有提到调试。它需要按设计工作,而不是通过寻找错误来工作。
有两个核心问题:
对数据结构的访问序列化。
僵局。
我在下面讨论的事件驱动或 CSP 方法会自动处理 #1。死锁问题并非微不足道,仍然是一个活跃的研究课题。即,证明没有死锁的方法(以及为它设计的方法!)。
使检查和正式证明某些属性(如免于死锁)变得更容易的设计示例之一是通信顺序进程 (CSP)。
CSP 方法在大多数应用程序开发框架中都可用,并且可以实现为无共享的事件驱动系统。核心特点是:
只要更高级别的抽象不使用事件传递来重新实现容易死锁的抽象,这本身就可以确保免于死锁。例如,即使通过事件传递也可以获得哲学家就餐问题的死锁,但您现在通过事件(消息)显式传递有关资源的信息。因此,这个问题至少是明确的,你不得不考虑它。可以这么说,问题并没有被掩盖。
证明不会发生死锁/活锁的正式技术可以更容易地应用于实现 CSP 的事件传递生产代码。事件接受代码可以提供运行时自省,允许提取每个状态的已接受事件集以及状态集(在内部它是一个状态机)。此信息通常足以证明没有死锁的可能性,或者可以列举一小组死锁场景,然后可以以其他方式处理这些场景。毕竟,CSP 形式主义通常不能捕获软件的完整语义,因此语义本身可用于进一步表明没有发生死锁,或者以其他方式处理死锁。