“例如只有一个低优先级持锁者,其剩余临界区服务至多3;被分析任务是系统最高优先级,所需自身服务为1,没有其它锁、嵌套或自挂起。基本继承使中优先级工作不能插入这3单位服务,因此B=3给R≤4。这…”
形式陈述
等待的是锁,推进却依赖另一个线程获得CPU
本页把带所有者的互斥锁理路互斥锁Mutex · Mutex lock · 互斥量以获取、释放与所有权封装临界区互斥的同步对象。加入单核可抢占服务账本理路CPU服务、就绪与时间账本CPU service accounting · CPU burst · Ready time · Preemptive scheduling model用实际服务量、剩余量和就绪等待刻画单核调度,固定同刻事件顺序,并把墙钟时间分成运行、阻塞和等待。。每个线程有固定基础优先级p,数值越小越高;实际派发看有效优先级e。线程可能同时持有多把锁,但一次最多挂起一个获取请求;被锁阻塞时没有运行资格。仅提高被阻塞线程自己的优先级不能释放锁。
当前等待图有边u→v,当且仅当u正在等待一把由v持有的锁。基本优先级继承让持锁者取得所有直接、间接等待者中最高的优先级。可精确定义为
于是任意等待边u→v都满足e(v)≤e(u)。一个本来只排在低优先级的持锁者,会代表被它挡住的高优先级请求向前运行;互斥所有权本身不被夺走。[1, §III.A]
本页不把实时任务的无锁可行性判据直接沿用到这里。锁扩展允许嵌套等待,只有另行排除死锁、自挂起和无界临界区后,才有望推导响应上界。
原子管理器维护的状态
锁记录owner或空闲,线程记录基础优先级、held集合、pending锁或无,以及READY/BLOCKED/DONE。每次管理器动作在调度选择之外原子完成:
- 获取空闲锁,登记所有者与held;获取已占用锁,登记pending并转BLOCKED,添加等待边。非递归锁上再次获取自己持有的锁不被当成成功
- 释放只能由所有者执行。先移除旧所有权;若有等待者,按当前有效优先级、再按固定线程名选一个,直接交付所有权,清除其pending并转READY。其它等待者的目标变成新所有者
- 取消一个等待请求时,只删该pending及对应等待边并转READY;线程此前持有的其它锁不会凭空释放。取消也不回滚临界区里的业务修改
- 每次边或所有权改变后,从全部基础优先级重新计算上式,更新所有就绪选择键,再允许下一次派发。DONE只允许在线程没有held、也没有pending时发生
下载器用从p初始化的反复松弛:对每条u→v令e(v)=min(e(v),e(u)),直到不变。它不是只在第一次阻塞时提升一次,也不是释放任意一把锁就无条件恢复基础优先级。
直觉
把CPU临时给真正能解除等待的人
设H、M、L基础优先级依次为1、2、3。L拿着H需要的锁,H因等待而不就绪;如果调度器只看基础优先级,它会让无关的M抢占L。H虽然比M更重要,却间接等M做完,这就是优先级反转。
继承加入H→L后,使e(L)=1。M的2不再能抢占L,L可以先完成保护中的修改并释放锁,随后H真正取得锁。它改变的是持锁期间的派发资格排序,没有让两个线程同时进入临界区。
传播和撤销必须面对整张当前图
若H等待M持有的锁,而M又等待L,图为H→M→L。只把M提升到1仍不够,因为M是BLOCKED;L也必须得到1,才能阻止一个基础优先级2的无关线程插入。松弛直到稳定,正好把H的优先级传到链尾。
归纳看,第k轮后至少包含长度≤k的等待路径来源。n个线程的可达路径若能到达,就存在长度≤n−1的简单路径,因此至多n−1轮传播后上式全部成立;随后一轮确认不变。即使存在环,有限优先级闭包仍可计算,这不表示环中的线程恢复了运行资格。
边删除时,从旧e继续只做min无法降级。例如H取消等待后,旧的1会永远留在L上。每次从基础p重算可以撤销已经失去来源的继承;优化实现也必须维护等价的捐赠来源信息。
例子与边界
从10完成,改成5完成
L在0取得锁m,临界区需4单位CPU;H在1释放,立即请求m,取得后还需1单位CPU;M在2释放,需5单位CPU且不用m。管理动作与切换按零成本,L释放m后本例即完成。
| 区间 | 无继承运行者 | 有继承运行者 |
|---|---|---|
| [0,1) | L,剩余临界区3 | L,剩余临界区3 |
| [1,2) | L,H被锁阻塞 | L继承H的1 |
| [2,4) | M抢占L | L继续直到释放m |
| [4,5) | M | H获锁并完成 |
| [5,7) | M直到做完 | M |
| [7,9) | L补完临界区 | M |
| [9,10) | H获锁并完成 | M继续并在10完成 |
无继承时L在9才释放,H在10完成;继承时L在4释放,H在5完成。若H相对期限为4,则deadline=5,有继承恰好按时。H从1到4的锁阻塞包含L剩余3单位服务,H自己的1必须另算。[1, §II Example 1及§III]
释放一把锁,不一定回到基础值
L基础优先级4,同时持有a和b。H基础1等待a,M基础2等待b,此时e(L)=1。L释放a并交给H后,H→L消失,但M→L仍在,所以e(L)=2,不能直接恢复4。等b也释放后才恢复4。
取消也一样:如果H撤销a的等待,L仍持有a/b,但当前最高捐赠只剩M的2。若再取消M,L才回到4。历史上曾经继承过谁,不能替代当前边集合。
继承不会破坏锁等待环
X持有a并等待Y的b,Y持有b并等待X的a。两者即使都得到最高优先级,仍都BLOCKED,没有人能执行unlock。死锁理路死锁Deadlock · 资源死锁一组参与者因等待依赖闭合而彼此无法再完成所需动作的全局进展失败。需要一致锁序、可回退协议或检测恢复等额外机制;原论文讨论基本继承的阻塞性质时也先假定死锁由外部办法排除。[1, §III.B/C]
基本继承也不保证一份高优先级作业只等一个低优先级临界区。它先等L释放a,继续后再请求M已持有的b,就可能顺序等待两段。把“最长单个临界区”直接作为任意PIP的总B,会低估响应。原论文的天花板协议增加了另一套准入规则,本页没有实现,不能借用它的单次阻塞结论。
推论与应用
一个可以接入响应分析的受限界
若被分析H是最高优先级,只请求一把锁;释放H时至多一个L已持有它,剩余临界区CPU服务≤b;持锁期间没有其它锁等待、自挂起或故障,H取得后需求≤C_H,那么继承后中优先级线程不能插队,得到R_H≤b+C_H。
这个界的每个条件都有用。去掉剩余临界区上界,b可能无限;让L等待I/O,单靠CPU继承不能推动设备;加入锁链,必须算链中的额外服务;允许更高优先级线程,则还要计它们的干扰。响应分析理路固定优先级响应时间分析Fixed-priority response-time analysis · Response time analysis · RTA schedulability在独立可抢占约束截止期模型中逐次计入高优先级干扰,计算最小响应时间不动点,并区分政策失败与任务集不可行。中的B应由这样的具体资源模型产生。
状态正确,与低开销是两件事
设n个线程、e条当前等待边。朴素闭包最多O(n)轮,每轮扫描e条边并检查变化,花O(n(1+e))时间。若共有ℓ把锁,所有权、held和等待边合计需O(n+ℓ+e)状态;本页一个线程最多等待一把锁,故e≤n。按有效优先级扫描选READY者再花O(n)。释放时扫描至多n个等待者、检查所有权,以及每事件保存O(n+ℓ)的完整状态日志,都是下载核验器的额外工作,未把它包装成常数时间内核路径。
更高效实现可以为每把锁维护优先级等待队列,为每个持锁者维护各锁带来的最高捐赠,再沿受影响链更新。无论结构怎样换,都必须在交接、取消及多锁释放后保持相同闭包和所有权不变量。
截止期证书终点最后要求交出锁事件前后的owner/pending/e,而不只是画一个“L变高”的箭头。只有明确谁仍在等谁,才知道该保留还是撤销继承。
参考资料
- Lui Sha、Ragunathan Rajkumar、John P. Lehoczky,Priority Inheritance Protocols: An Approach to Real-Time Synchronization,IEEE Transactions on Computers39(9),1990,pp.1175–1185;§II,p.1176定义反转和假设;§III.A,p.1177规定传递及原子性;§III.B/C,pp.1177–1178讨论阻塞与死锁。本文的显式等待图、取消动作和整体重算是便于复核的实现展开,未声称覆盖原文全部运行时优化。
- The Open Group,pthread_mutexattr_getprotocol / pthread_mutexattr_setprotocol,POSIX.1-2024,DESCRIPTION中PTHREAD_PRIO_INHERIT说明递归传播和多锁继承。具体API支持、调度类别与错误条件仍由实现合同决定;本文不模拟某一操作系统API。