我们先从两个虽然存在不足但却十分有趣的锁算法讲起。
LockOne类
双线程的锁算法遵循以下两点约定:线程的标识为0或1,若当前调用者的标识为i,则另一方为j = 1 - i;每个线程通过调用ThreadID.get()获取自己的标识。
用writeA(x = v)表示A将值v赋予域x,用readA(v == x)表示A从域x中读取值v。在值不重要的情形下,可以省略v。下图的writeA(flag[i] = true)事件是由lock()方法中第9行代码的执行所引起的。
Code
LockOne算法虽然满足互斥特性,但存在着缺陷,其原因在于线程交叉执行时会出现死锁。若事件writeA(flag[A] = true)及writeB(flag[B] = true)在事件readA(flag[B])和readB(flag[A])之前发生,那么两个线程都将陷入无穷等待。然而,LockOne算法有一个有趣的特点:如果一个线程在另一个线程之前运行,则不会发生死锁,一切都工作得很好。
LockTwo类
Code
LockTwo类也存在缺陷,当一个线程完全先于另一个线程就会出现死锁。但是如果线程并发地执行时,setlock()方法则是成功的。LockOne类和LockTwo类彼此互补:能够保证一种解法正常工作的条件将会使另一种解法发生死锁。
Peterson锁
该算法将LockOne和LockTwo结合起来,无疑是最简洁、最完美的双线程互斥算法,按照其发明者的名字被命名为“Peterson算法”。
Code
LockOne类
双线程的锁算法遵循以下两点约定:线程的标识为0或1,若当前调用者的标识为i,则另一方为j = 1 - i;每个线程通过调用ThreadID.get()获取自己的标识。
用writeA(x = v)表示A将值v赋予域x,用readA(v == x)表示A从域x中读取值v。在值不重要的情形下,可以省略v。下图的writeA(flag[i] = true)事件是由lock()方法中第9行代码的执行所引起的。

LockOne算法虽然满足互斥特性,但存在着缺陷,其原因在于线程交叉执行时会出现死锁。若事件writeA(flag[A] = true)及writeB(flag[B] = true)在事件readA(flag[B])和readB(flag[A])之前发生,那么两个线程都将陷入无穷等待。然而,LockOne算法有一个有趣的特点:如果一个线程在另一个线程之前运行,则不会发生死锁,一切都工作得很好。
LockTwo类

LockTwo类也存在缺陷,当一个线程完全先于另一个线程就会出现死锁。但是如果线程并发地执行时,setlock()方法则是成功的。LockOne类和LockTwo类彼此互补:能够保证一种解法正常工作的条件将会使另一种解法发生死锁。
Peterson锁
该算法将LockOne和LockTwo结合起来,无疑是最简洁、最完美的双线程互斥算法,按照其发明者的名字被命名为“Peterson算法”。

分类:
读书笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)