经典互斥算法
操作系统5--信号量机制

的原子操作来访问.
1、整型信号量机制 2、记录型信号量机制 3、信号量集机制
5.1/28 2011
操作系统
1、整型信号量机制
1).整型信号量 是一个整数,表示空闲资源总数(又称为“资源信号量”) ----若为非负值表示当前的空闲资源数, ----为负值其绝对值表示当前等待临界区的进程数 ----初值应该大于零。
5.19/28
2011
操作系统
A.采用记录型信号量机制
Wmutex:互斥信号量:表示“允许写”,初值是1。 公共变量Readcount表示“正在读”的进程数,初值是0; Rmutex:互斥信号量:表示对Readcount的互斥操作,初值是1。
reader writer
Wait(Wmutex); Write; Signal(Wmutex); wait(Rmutex); if(Readcount=0) then wait(wmutex) Readcount=Readcount+1; Signal(Rmutex); //关闭写的同时允许读(无上限) read; Wait(Rmutex); Readcount:=Readcount-1; if Readcount=0 then signal(Wmutex); Signal(Rmutex); //适当的时候打开写
两个原子操作即: P,V操作。也常称为wait(s),singal(s)
(P、V分别是荷兰语的test(proberen)和increment(verhogen)) 即: P(s): Wait(s): while s<=0 do no_op s:=s-1; V(s): Singal(s): s:=s+1;
一种改进的主副本分布式锁

摘要 : 分布式互斥 是分布式系统 【的 亟要问题之 一。通过对 分 布式锁 的使 f , } 一种基 于涣 请求作 不 同 I | }提 I J I 加锁处理的主副本锁。同时给 } 了执行方案 , f J 对其性能进行 了分析 。最后 , 与传统 主副本锁进 行 了比较 , 证明其高
效性。 关 键 词 : 副 本 锁 ; 布 式 数 据 库 ; 信 量 主 分 通
2 1 主 要思 想 .
传统 的主副本分布式锁选择某个节点上的副本为主副本 , 所有的读写操作均 申请对主副本的锁 , 每个资源都 指定 一个节 点 , 负责 锁 的控 制 , 此节 点称 为该 数据 的 主节 点 ( r r i ) pi yse 。当 申请 资 源 的锁 时 , 管 它 有 多少 副 ma t 不 本和副本位于何处均需到该资源的主节点进行申请 。由于锁申请 由主节点统一管理 , 多副本 的锁管理机制如 同 单 副 本一样 。如 果事 务就 发生 在主 节 点 , 则锁 的 通信 开 销 可 以免 去 。主 节 点 一 般选 在 使 用 该 资 源 最 多 的节 点 。 主副本 锁机 制可 以避 免死 锁 的产生 。 在传统的主副本锁机制中, R 锁 也需 要扩散到整个 系统中从而造成加锁过程中通信次数 的增加。在分 读( ) 布式数据库中, 时间延迟多为加锁操作中的网络通信开销。在读操作较频繁的系统中, 这将导致整个系统的运行 速 度下 降 。
VD. 2 NO 5 12 . Oc .2 0 t 07
文章编号 :I7I14 l(1)51 9 一4 6 .7 22171 一5 8( ( )) 1
一
种 改 进 的 主 副 本 分 布 式 锁
朱 静 , 刘心松 , 王 征
( 电子科技 大 学 8 1 究室 ,- 成 都 6 0 5 ) 0 0研 v川 - q 10 4
读者-写者问题说明书

《操作系统原理》课程设计任务书题目:读者-写者问题的实现学生姓名:李志旭学号:13740113 班级:_13级软件工程_题目类型:软件工程(R)指导教师:陈文娟、马生菊一、设计目的学生通过该题目的设计过程,掌握读者、写者问题的原理、软件开发方法并提高解决实际问题的能力。
二、设计任务编写程序实现读者优先和写者优先问题:读者-写者问题的读写操作限制(包括读者优先和写者优先)写-写互斥:不能有两个写者同时进行写操作读-写互斥:不能同时有一个线程在读,而另一个线程在写。
读-读允许:可以有一个或多个读者在读。
三、设计要求1.分析设计要求,给出解决方案(要说明设计实现所用的原理、采用的数据结构)。
2.设计合适的测试用例,对得到的运行结果要有分析。
3.设计中遇到的问题,设计的心得体会。
4.文档:课程设计打印文档每个学生一份,并装在统一的资料袋中,资料袋前面要贴有学校统一的资料袋封面。
四、提交的成果1. 课程设计说明书内容包括(1) 封面(学院统一印制);(2) 课程设计任务书;(3) 中文摘要150字;关键词3-5个;(4) 目录;(5) 正文;(设计思想;各模块的伪码算法;函数的调用关系图;测试结果等)(6) 设计总结;(7) 参考文献;(8) 致谢等。
注:每一部分是单独的一章,要另起一页写。
2. 排版要求(1) 所有一级标题为宋体三号加粗(即上面写的2~8部分,单独一行,居中)(2) 所有二级标题为宋体四号加粗(左对齐)(3) 所有三级标题为宋体小四加粗(左对齐)(4) 除标题外所有正文为宋体小四,行间距为固定值22磅,每个段落首行缩进2字符(5) 目录只显示3级标题,目录的最后一项是无序号的“参考文献资料”。
3. 其他要求(班长负责,务必按照以下方式建文件夹)(1) 以班级为单位刻录光盘一张,光盘以班级命名,例如:“10级计算机科学与技术1班”;(2) 光盘内每人一个文件夹,以学号姓名命名——如“10730101 陈映霞”,内容包括任务书、设计文档。
pv操作题目 软考

PV操作在软考中的深入探讨1. 基本概念PV操作是用于进程同步的两种基本操作。
P操作通常表示为一个进程需要一个资源,而V操作表示释放一个资源。
这两种操作通常用于实现进程间的同步和互斥。
2. PV操作原理PV操作基于信号量机制。
信号量是一个整数值,通常用于表示资源的数量。
P操作会尝试获取资源,减少信号量的值;而V操作会释放资源,增加信号量的值。
如果P操作不能立即获得资源(即信号量为0),则该进程会被阻塞或等待,直到资源可用。
3. PV操作在进程同步中的应用PV操作在进程同步中有着广泛的应用。
例如,在生产者-消费者问题中,生产者用于生成数据,消费者用于消费数据。
通过PV操作,可以确保生产者在没有数据被消费之前不会继续生产,同时确保消费者在没有数据可供消费时不会继续消费。
4. PV操作和互斥量互斥量是一种特殊的信号量,其值只能为0和1。
当一个进程获得互斥量时,其他任何进程都无法获得该互斥量,直到第一个进程释放它。
这使得互斥量可以用于保护某些临界区域,以实现互斥访问。
PV操作和互斥量通常一起使用,以实现更复杂的同步问题。
5. PV操作的编程实现在大多数编程语言中,PV操作可以通过系统调用或库函数实现。
例如,在UNIX系统中,可以使用semop函数进行PV操作。
在实现PV操作时,需要注意避免死锁和饥饿等问题。
6. PV操作的复杂度分析PV操作的复杂度取决于所使用的算法和数据结构。
在一些算法中,例如二叉堆或斐波那契堆,PV操作的平均时间复杂度可以达到O(1)。
然而,在最坏的情况下,PV操作的复杂度可能会达到O(n),其中n是信号量的值。
7. PV操作与信号量信号量是一种同步机制,用于控制多个进程对共享资源的访问。
PV操作是信号量机制中的基本操作,通过它们可以实现对共享资源的互斥访问和同步。
信号量通常用于保护临界区、实现进程间的同步和互斥等。
8. PV操作与死锁预防死锁是操作系统中的一个重要问题,它发生在两个或多个进程无限期地等待对方释放资源的情况。
龙门同步算法

龙门同步算法龙门同步算法是一种用于多线程编程的同步机制,用于协调多个线程之间的操作顺序,以保证数据的一致性和正确性。
本文将介绍龙门同步算法的原理、应用场景以及其在实际开发中的使用方法和注意事项。
一、龙门同步算法的原理龙门同步算法是基于信号量机制实现的一种同步机制。
信号量是一种用于控制并发访问的计数器,通过对信号量的操作(比如P操作和V操作)来实现线程的同步和互斥。
而龙门同步算法则是在信号量的基础上进行了进一步的优化。
龙门同步算法的核心思想是引入了龙门和龙珠的概念。
龙门相当于一个互斥锁,用于控制临界区的访问权限,而龙珠则相当于一个信号量,用于控制线程之间的同步。
当一个线程需要进入临界区时,首先要获取龙门,如果龙门已经被其他线程持有,则该线程会被阻塞;当线程执行完临界区的操作后,需要释放龙门,以便其他线程可以获取并进入临界区。
龙门同步算法适用于多线程访问共享资源的场景,特别是当多个线程需要按照一定的顺序执行时,龙门同步算法可以保证线程之间的顺序执行,从而避免数据竞争和不一致性的问题。
例如,在生产者-消费者模型中,生产者线程负责生产数据,消费者线程负责消费数据,而且消费者线程必须在生产者线程生产完数据后才能进行消费。
这时就可以使用龙门同步算法来保证生产者线程和消费者线程的顺序执行,从而避免数据的丢失或重复消费。
三、龙门同步算法的使用方法和注意事项使用龙门同步算法进行多线程编程时,需要注意以下几点:1. 确定临界区:首先需要确定哪些代码块是临界区,即多个线程需要同步执行的部分。
2. 创建龙门和龙珠:根据需要同步的线程数量,创建对应数量的龙门和龙珠。
3. 获取龙门和释放龙门:在线程需要进入临界区时,调用龙门的获取方法,如果龙门已经被其他线程持有,则当前线程会被阻塞;在线程执行完临界区操作后,需要释放龙门,以便其他线程可以获取。
4. 处理异常情况:在使用龙门同步算法时,需要考虑异常情况的处理,比如防止死锁和饥饿等问题。
mifare classic 认证算法

mifare classic 认证算法Mifare Classic是一种使用不对称密钥进行认证的智能卡技术,广泛应用于门禁系统、电子钱包、交通票务系统等领域。
它采用了基于DES算法的认证算法,以确保卡片与读写器之间的通信安全性。
本文将详细介绍Mifare Classic的认证算法,并逐步解释其实现过程。
第一步:密钥管理在Mifare Classic认证算法中,密钥管理是非常重要的一步。
每个Mifare Classic卡片都存储有若干个扇区(Sector),每个扇区有一个密钥用于验证卡片的合法性。
通常情况下,每个扇区都使用两个密钥,分别被称为A 密钥和B密钥。
其中,A密钥用于进行读操作,而B密钥则用于写入和读取操作。
第二步:互斥操作在Mifare Classic卡片中,对于每个扇区来说,同一时间只能有一个密钥与之关联。
这就要求在进行认证操作之前,必须先获取扇区独占访问权限。
这一过程称为互斥操作,其目的是确保每次只有一个密钥能够与目标扇区进行通信。
第三步:认证过程认证过程是Mifare Classic算法的核心部分。
在这一步中,读写器会发送一个特殊的命令给Mifare Classic卡片,要求其使用指定的密钥对目标扇区进行认证。
具体的认证过程如下:1. 读写器向卡片发送认证命令,其中包含了要认证的扇区号及相应的密钥类型(A密钥或B密钥);2. 卡片接收到命令后,首先检查是否存在互斥操作。
如果有其他密钥正在与目标扇区通信,卡片会进行等待,直到获得访问权限;3. 卡片读取目标扇区的密钥,并使用该密钥对一个随机数进行加密;4. 卡片将加密后的结果发送给读写器,并同时记录所使用的密钥类型;5. 读写器使用相同的密钥对收到的加密结果进行解密,得到卡片发送的随机数;6. 读写器将自己生成的另一个随机数,以及解密后的卡片随机数,通过一个哈希函数进行运算,得到一个消息认证码(MAC);7. 读写器将生成的MAC发送给卡片;8. 卡片用相同的哈希函数对自己生成的随机数进行运算,并与收到的MAC进行比较。
第二部分 考前第5天 概率与统计、推理证明、算法

解决程序框图问题时, ❻ 解决程序框图问题时,一定要仔细分析程序框图的 实际意义是什么,也就是这个程序框图要计算的是什么, 实际意义是什么,也就是这个程序框图要计算的是什么, 这个计算是从什么时候开始、中间按照什么规律进行、 这个计算是从什么时候开始、中间按照什么规律进行、最 后计算到什么位置.这是分析程序框图的一个基本思路. 后计算到什么位置.这是分析程序框图的一个基本思路.
[尝试 尝试3] 若将一枚质地均匀的骰子 一种各面上分别标 若将一枚质地均匀的骰子(一种各面上分别标 尝试 个点的正方体玩具)先后抛掷 有1,2,3,4,5,6个点的正方体玩具 先后抛掷 次,则出现向 个点的正方体玩具 先后抛掷2次 上的点数之和为4的概率为 上的点数之和为 的概率为____________. 的概率为 .
[尝试 7] 尝试 +b= = A.1 . B.0 . C.- .-1 .- D. 3 2 1+2i + (2011·辽宁协作体 辽宁协作体) 辽宁协作体 =2-i,a∈R,b∈R,则 a -, ∈ , ∈ , a+bi + ( )
[答案 A 答案] 答案
❽类比推理用一类事物的性质去推测另一类事物的性 猜想), 质,得出一个明确的命题(猜想 ,类比的结论不一定正 得出一个明确的命题 猜想 确. 归纳推理是由部分推知整体的一种合情推理, 归纳推理是由部分推知整体的一种合情推理,和 类比推理一样, 合乎情理 是其主要特征, 合乎情理”是其主要特征 类比推理一样,“合乎情理 是其主要特征,即我们作 出的归纳首先要适合“部分 . 出的归纳首先要适合 部分”. 部分
应用互斥事件的概率加法公式, ❶ 应用互斥事件的概率加法公式,一定要注意首先确 定各事件是否彼此互斥, 定各事件是否彼此互斥,然后求出各事件分别发生的 概率,再求和. 概率,再求和.
操作系统20

一、选择题(每题1分,共30分)1. 在Hoare管程中,signal操作的语义是______。
A. signal and leaveB. signal and urgent waitC. signal and continueD. signal and entry wait2. 忙式等待的进程处于______状态。
A. 等待状态B. 运行状态C. 就绪状态或运行状态D. 就绪状态3. 经典UNIX系统采用的互斥方法是______。
A. 开关中断B. 软件互斥算法C. PV操作D. 自旋锁4. 在段页式存储管理中,逻辑地址为(s,p,d),其中______可能越界。
A. s和dB. p和dC. s和pD. s、p、d都5. UNIX操作系统的进程调度算法是______。
A. 可抢占CPU的HPF算法B. RR算法C. FB算法D. HRN算法6. CPU执行______时所花的时间不属于系统开销。
A. 用户程序B. 死锁检测程序C. 处理机调度程序D. 缺页中断处理程序7. 在下列调度算法中,______可用于实时调度且属于剥夺式(可抢占式)调度算法。
A. RMS算法B. EDF算法C. FB算法D. HRN算法8. 适合分布环境的同步机制是______。
A. 信号灯与PV操作B. 管程C. 会合D. 条件临界区9.作业调度是从输入井中处于______ 状态的作业中选取作业调入主存运行。
A. 运行B. 完成C. 提交D. 后备10.Hash文件采用的寻址方法主要是以______ 为主。
A. 计算B. 比较C. 索引D. 顺序11. 可能发生Belady异常的页面置换算法是______。
A. FIFO算法B. NUR算法C. LRU算法D. LFU算法12.在Solaris系统中,用户和系统均可见的成分是______。
A. 用户级线程B. 核心级线程C. 轻进程D. 系统线程13.某计算机系统中有8台打印机,由K个进程竞争使用,每个进程最多需要3台打印机。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2 经典互斥算法 每一个线程都有一个私有变量 i 表示自己的 id,由于有两 个线程,所以 i 的取值为 1 或者 2,因此 other = 3 − i 取值 表示下一轮应该轮到谁进入临界区了。 算法 1 Dekker 算法 1: status[i] = competing;
2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
Dijkstra 算法,因为 Dijkstra 算法通常指的
是求图中最短路径的算法。
2 经典互斥算法
3
后来都反对 [Dij68b] 的 go to 语句。所以这里列出的算法 N 个线程的情况,结构同样很简单。我们先看 2 线程的 对原文的算法结构进行了一些调整,使其更适合当代的 Peterson 算法,如算法 3 所示。算法中 q 是一个二元组, 阅读习惯。从算法的结构可以看出,在临界区之前的 lock q[1] 由线程 1 操作,q[2] 由线程 2 操作,两个值的初始值 部分包含一个循环,循环内部是一个 if 判断语句,根据 条件将循环体分割为两部分。假设 N 个线程都在竞争临 界区,根据第 3 行的条件,只有一个线程能进入 else 部 分,即第 7–8 行,这个线程也就是 k 表示的那个线程。这 个线程判断是否除了自己的 c[i] 之外其他所有线程的 c[i] 都为 true,如果满足的话则退出循环进入临界区。这个 条件显然最后是可以满足的,因为所有其他的线程都在 循环执行 if 条件满足的那一部分,因此一定会将自己的 c[i] 设置为 true。当 k 表示的这个线程完成了临界区之后, 会将 c[i] 和 b[i] 都设置为 true。这时,除了线程 k 之外的 所有其他的线程的第 5 行的 if 条件都会满足,因此执行 k = i,试图将 k 设置为自己。最终 k 总会表示某一个正 在竞争的线程,这个线程进入 else 部分循环,而且此时 b[k] == false,所以其他失败的线程依然在第 4–5 行循环 执行,并且还会争相将自己的 c[i] 设置为 true,让抢到了 k 的线程能够尽快进入临界区。所以可以看出, Dijkstra 提出的算法解决了 N 个线程之间的互斥问题。 都为 false。 turn 是两个线程共享的一个整型变量,初始 值可以是 1 或 2。 算法 3 Peterson 算法(2 线程) 1: q[i] = true;
接在总线上访问或通过互联网络访问或通过多核处理器 互斥问题最早是 Edsger W. Dijkstra1 在 1965 年的 ACM 内部的互联网络访问。为了统一术语,本文使用最常用的 通讯中正式提出的 [Dij65]。文中的问题描述如下:有 N 多线程编程使用的术语。 台计算机都在重复执行某项任务,这项任务中有一段称 为 “临界区”,要求同一时刻这 N 台计算机中只能有一台 在临界区中。计算机之间可以通过共享的存储空间协调 访问临界区。写入和读取临界区的操作是不可分割的。解 决方法必须满足以下特点: 1. N 台计算机是对称的,没有指定的优先级;
1
互斥问题的定义
互斥(mutual exclusive)是我们现在进行多线程编程
每一次只能发出一次读写请求,按照现在的话说,就是在 的一个基本工具。本文探寻分布式计算历史上的几个非 缺少 read-modify-write 这类原子操作的情况下要实现互 常有名非常经典的互斥算法,尽管这些算法几乎是所有 斥是很难的。 操作系统、分布式系统或多线程编程课本中必介绍的算 法,可是由于这些算法由于性能问题已经被现代的算法 或机制替代了,实际中不会有人使用这些算法。尽管如 此,了解这些算法可以帮助我们理解同步领域的基本原 理。此外,了解这些算法的正确性证明可还可以训练并发 算法正确性推导的思维。 在那个没有多核处理器或多处理器计算机的年代, 一台 “计算机” 同时只能执行一个线程,所以原文中的 “计 算机” 用现在的话来说就是一个处理器或多核处理器中的 一个核心或一个硬件线程, “共享的存储空间” 可以是线 程或进程间的共享内存,访问共享内存的方式可以是直
* zhengsyao@,/zhengsyao/ 1 Edsger
2
2.1
经典互斥算法
Dekker 算法
Dekker 算法是第一个正确地通过软件方法解决两
W. Dijkstra 是计算机发展历史上的重要人物,除了耳熟能详
线程互斥问题的算法,该算法最早由 Dijkstra 在 [Dij68a] 中 描 述, 算 法 1 就 是 Dekker 算 法。 算 法 中 的 status[1] 和 status[2] 分 别 表 示 两 个 线 程 的 状 态, 状 态 可 以 取 值 competing 和 out。如果状态取值 competing,表示当前线 程处于正在竞争进入临界区的状态;如果状态取值为 out, 则表示这个线程放弃尝试进入临界区或已经退出临界区。 1
2 本文不把这个算法称为
算法 2 Dijkstra 提出的算法 1: b[i] = false;
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
loop if k ≠ i then c[i] = true; if b[k] == true then k = i; else c[i] = false; if ∀j ≠ i, c[j] == true then break; end if end loop 临界区; c[i] = true; b[i] = true;
经典互斥算法
郑思遥* 2013 年 1 月 4 日
摘要
本文用较为轻松的方式介绍了几个经典的互斥算法: Dekker 算法、 Dijkstra 提出的算法、 Peterson 算法和面包 店算法,并简单地给出了每一个算法的正确性证明和相 关的讨论。
2. 对 N 台计算机的速度不做任何假设,甚至同一台计 算机的速度也不一定是固定不变的; 3. 如果某台计算机在临界区之外停机了,那么不允许 导致其他计算机阻塞; 4. 不允许发生 “Aer you”–“Aer you” 阻塞,也就是说, 如果所有计算机都没有在临界区中,那么必须允许 一个——只允许一个——计算机进入临界区。 这个问题看上去挺简单,其实不容易,因为每一台计算机
的计算最短路径的 Dijkstra 算法,他也是分布式计算领域的开创者,重 要成果包括信号量和哲学家就餐问题。 Dijkstra 卒于 2002 年,同年其 1974 年的论文 “Self-stabilizing systems in spite of distributed control” 被授 予 ACM PODC(Symposium on Principles of Distributed Computing)最有 影响力论文奖。为了纪念这位科学家,PODC 最有影响力论文奖在 2003 年更名为 Dijkstra 奖。
为 2 或者 1,表示另一个线程的 id。turn 是一个共享变量, 次变化只能由线程 2 来完成,所以线程 2 最终总能发现
while status[other] == competing do if turn == other then status[i] = out; wait until turn == i; status[i] = competing; end if end while 临界区; turn = other; status[i] = out;
2: 3: 4: 5:
turn = i; wait until not q[3 − i] or not turn == i; 临界区; q[i] = false; 在 lock 操作中,线程首先将自己的 q[i] 设置为 true,
并且试图将 turn 设置为自己。第 3 行的等待循环判断两 个条件,如果有一个为真就进入临界区。两个线程不可能 同时通过第 3 行的判断条件,因为如果两个线程都到达这 一行了,那么 q[1] 和 q[2] 都为 true,所以只能同时满足 判断的后一个条件,而 turn 不可能同时为两个值,所以 两个线程只能先后通过这个条件。假设线程 1 通过了这个 条件判断,进入了临界区。那么此时必满足 q[2] == false
这个算法中的采用的变量名初看上去不好理解, 实际 和 turn == 2 中至少一个条件。如果满足前者,说明线程 上对照算法 1 中使用的变量名,数组 b[1 ∶ N] 和 c[1 ∶ N] 2 已经退出临界区或还没有开始竞争临界区,如果线程 2 共同表示了线程的状态,整数 k 实际上等同于 turn。 开始竞争进入临界区,那么必然无法通过第 3 行的判断条 Dijkstra 提出的算法有一个问题就是不能防止线程饿 死。如果有一个线程获得了 k,而且这个线程反复试图访 问临界区,假设这个线程很快进入 lock 部分的代码,将 b[k] 设置为 false,那么其他线程有可能永远都在循环中 等待。这个问题很快被 Knuth 发现了 [Knu66](对,就是 件。如果满足后者,说明线程 2 已经执行完成了第 2 行, 此时由于线程 1 仍然在临界区,所以 q[1] 为 true,因此线 程 2 仍然无法通过第 3 行的判断条件。因此,这个算法可 以保证两个线程互斥访问临界区。另外也可以看出,这两 个线程都不会饿死。假设线程 1 在第 3 行的循环等待,线
2.2
Dijkstra 提出的算法
Dijkstra 在 [Dij65] 文中正式提出了并发编程中的互
斥问题并给出了一个解决方法。和 Dekker 算法不同的地 方在于,Dijkstra 提出的算法支持 N 个线程同时竞争临界 区,算法如算法2所示2 。这个算法使用了 2 个共享的数组
以第 9 行表示的临界区为界,之前的操作是试图进 b[1 ∶ N] 和 c[1 ∶ N], N 表示最大的线程数。这两个数组 入临界区之前要执行的操作,相当于互斥锁中的 lock 操 的 b[i] 和 c[i] 只能由线程 i 写入,但是可以由所有线程读 作,之后的操作是执行完临界区之后要执行的操作,相 取。还有一个共享整数变量 k,满足 1 ≤ k ≤ N,所有线程 当于 unlock 操作。线程在试图进入临界区的时候,首先 都可以原子地读写这个变量。i 是线程的私有变量,表示 将自己的状态标记为正在竞争进入临界区。然后通过第 自己的 id。 b[1 ∶ N] 和 c[1 ∶ N] 的初始值都为 true, k 的 2–8 行的 while 循环反复检查对方是否放弃或结束执行临 初始值可以是 [1 ∶ N] 之间的任意值,具体值无所谓。 界区。如果对方没有竞争,则直接进入临界区。如果对方 正在竞争,而且下一轮还轮到对方的话,那么自己首先放 弃,然后在第 5 行等待对方将 turn 让与自己,然后自己 再宣布进入竞争状态。如果下一轮即将轮到自己,那么回 到 while 循环等待对方完成临界区操作。 首先理解这个算法为什么能实现两个线程的互斥。 对于一个试图进入临界区的线程来说,如果另一个线程 没有这个企图,那么很简单直接进入临界区即可。如果 两个线程同时在竞争进入临界区,那么根据第 3 行的条件 判断,只有一个线程能够进入这个 if 语句,进入的这个 线程将自己的状态设置为放弃,所以给另一个线程进入 临界区的机会。另一个线程进入了临界区之后,会将 turn 设置为对方,所以放弃竞争临界区的线程又可以重新竞 争临界区。从这个描述可以看出这个算法可以保证两个 线程的互斥。 要理解这个算法要从这个算法的整体结构入手。原 再来看这个算法是否会导致一个线程 饿死。假设线 文 [Dij65] 中列出的算法代码使用的是 ALGOL 60 语言编 程 1 和线程 2 同时进入临界区, 并且不失一般性假设 写的,结构和缩进都比较混乱,还使用了 Dijkstra 他自己 turn = 1,那么两个线程进入 while 循环,其中线程 2 进入 if 语句。线程 2 将 status[2] 设置为 out,然后等待 turn 变