linux 内核有实时互斥体(锁),名为rt_mutex即realtime mutex。说到realtime一定离不开priority(优先级)。所谓实时,就是根据优先级的不同对任务作出不同速度的响应。rt_mutex也就是依据任务(task,process)的priority进行排队的锁,同时使用PI(priority Inheritance,优先级继承)算法解决proirty inversion(优先级逆转)的问题。 

这里有三个角色:rt_mutex,rt_mutex_waiter,以及task_struct。(pi算法与进程结构偶合在一起)

rt_mutex:实时锁,使用优先级排队,使用优先级继承算法解决优先级逆转问题,与task_struct强偶合。

task_struct:要求锁的任务,rt_mutex用其指针作为上锁状态。

rt_mutex_waiter:任务阻塞等待锁,即任务与锁的关联,代表任务对锁的一次需求。

rt_mutex和task_struct都有一个waiter有序队列,并且都实现为rb树,并以优先级prio进行排序。rt_mutex_waiter->tree_entry入队到rt_mutex(锁)的waiter队列,即rt_mutex->waiters。而rt_mutex_waiter->pi_tree_entry入队到task_struct(任务)的waiter队列,即task_struct->pi_waiters。

rt_mutex->waiters:用于阻塞等待排队,与pi chain无关。

task_struct->pi_waiters:并非用于排队,而是作为一个最小值计算器,为task_struct计算可继承的最小prio(最高),并且提供一个是否为空的判断属性。它收集了task持有的所有rt_mutex的leftmost_waiter,即每当一个task在一个rt_mutex上了锁,这个rt_mutex的waiters中prio最小(最高)的waiter将被入队到task_struct->pi_waiters。与pi chain无关。

rt_mutex_waiter->prio:rt_mutex->waiters和task_struct->pi_waiters两个队列都使用这个值进行排序。一个在pi chain上阻塞的任务,当优先级被boost后,同样会反映在waiter结构的prio上。

pi chain:从一个任务的task_struct->pi_block_on开始,依次进行rt_mutex = rt_mutex_waiter->lock,task_struct = rt_mutex->owner,rt_mutex_waiter = task_struct->pi_block_on访问遍历。这个链并非我们通过指的用链表结构进行链接的链表。而是 task -> waiter -> lock -> ... 的chain。虽然rt_mutex->waiters 和 task_struct->pi_waiters 同为队列(由rbtree实现),但是跟pi chain无关,pi chain walk路径不通过这两个队列。

以内核的设计文档rt-mutex-design.txt举例,有pi chain如下

Example:

   Process:  A, B, C, D, E
Mutexes: L1, L2, L3, L4 A owns: L1
B blocked on L1
B owns L2
C blocked on L2
C owns L3
D blocked on L3
D owns L4
E blocked on L4 The chain would be: E->L4->D->L3->C->L2->B->L1->A

在上面的例子中,A为最终的阻塞源,它继承了阻塞链上所有其它任务的优先级。图左则的任务被右则的任务阻塞,图右则的任务持有锁并继承图左则的任务的优先级。当一个任务被一个锁阻塞,并且这个锁在图上。以任务E为例,当E加入到pi chain后,就会从图的左则向图的右则进行pi chain walk,直到到达任务A,在walk所经节点,都会将优先级作最优继承。通常地pi chain由图最右则的A释放锁,一路唤醒pi chain上阻塞的任务,而消减pi chain。A首先离开pi chain,由于继承了优先级,必须马上恢复原有的优先级,但是并不需要进行pi chain walk,因为它是继承者不是继承源(没有pi_block_on),不影响其它继承者(pi chain上的任务)的继承。 但是如C,超时不阻塞了,要离开pi chain,因为它不但是继承者还是继承源(pi_block_on -> B),所以C必须对B进行pi chain walk。

下面是进行walk chain的调用拓扑,rt_mutex_adjust_prio_chain执行pi chain walk。

pi算法解决优先级逆转问题。

高(high)优先级任务由于等待低(low)优先级任务拥有的锁,在这过程中低优先级被其它优先级(界于高低之间的中级medium)的任务无限抢占,从而有机会释放锁,导致高优先级的任务无限等待。

下面设两轴,水平轴为时间,纵轴为优先级。

当一个high prio任务进来,抢占一个low prio任务后却发现有资源要同步又阻塞了,而这个同步的资源low prio任务正在使用,那么必须等待low prio任务释放掉同步的资源,high prio任务才能再次运行。但是有一种坏的情况是,low prio任务被medium prio任务抢占,不能及时释放同步的资源,使用high prio任务阻塞时间增加。

这还不算最坏的,最坏的是low prio任务被不定数目或不定回目的medium prio任务无限地进行抢占,最后导致high prio任务无限地被阻塞。

解决的方法就是,当high prio任务阻塞在一个同步资源时,将正在使用同步资源的任务临时提升 (boost)跟自己一样的优先级,赶紧释放资源,好让(方便)high prio任务通过。

rt_mutex->waiters 和 task_struct->pi_waiters 如何参与pi算法。

前面已经谈及的pi chain,也是pi算法的一部分。而pi算法的另一部分就是如何选出最高的优先级进行继承。这是通过rt_mutex->waiters和task_struct->pi_waiters队列来实现的。每当一个任务持有一个rt_mutex时,就会从rt_mutex->waiters中选出排在首位的waiter纳入到自己的task_struct->pi_waiters队列,这个同样是一个排序队列。这个队列代表着任务持有哪些rt_mutex,并且以及阻塞在这些rt_mutex的最高优先级(的任务)。这个队列将这些优先级进行排序选出最高的优先级进行继承。

一个对rt_mutex的lock或者unlock都可能会引发rt_mutex->waiters队列的入队和出队,从而改变了rt_mutex->waiters的排序,继而改变了task_struct->pi_waiters队列的成员,必须重新排序,选择新的优先级来继承。当pi chain上的一个任务的优先级继承受影响后,就必须要反映在它所阻塞的rt_mutex的waiters队列上,并按pi chain阻塞的方向传递变化。

任务 P 持有两个锁 L1 和 L2。A,B,C 阻塞在 L1;而 C,D,F 阻塞在 L2。 B 和 F 分别是 L1 和 L2 的 leftmost waiter,以最好的优先级 1 和 0,被任务 P 选中放在自己的 pi_waiters 队列。排序后,F 的优先级最高,作为继承的优先级。

当一个优先级更高的任务 X 需要阻塞在锁 L1 时,必然引发锁 L1的leftmost waiter改变,这时就要通知 P 选择 X 代替 B,重新对比 X 和 F 的优先级,选最高的优先级来继承。如果任务 P 还阻塞等待一个锁 L3 ,那么就必须进行 pi chain walk,通知优先级继承变更。

一个阻塞任务从其task_struct->pi_block_on开始进行 pi chain walk 通知优先级继承变更。

一个任务释放锁,从其task_struct->pi_waiters队列找出锁对应的任务进行唤醒。

linux 内核的rt_mutex (realtime互斥体)的更多相关文章

  1. linux 内核的rt_mutex 锁操作实现的临界区

    rt_mutex 定义的锁规则: 以偶对齐的task_struct指针为上锁标记, 偶对齐的指针地址最低位用以标记是否有waiters. rt_mutex的trylock,lock,以及unlock都 ...

  2. Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

    转自:http://blog.csdn.net/shanshanpt/article/details/21024465 在2.6.24之后这个结构体有了较大的变化,此处先说一说2.6.16版本的sk_ ...

  3. linux 内核的futex pi-support,即pi-futex使用rt_mutex委托

    futex的pi-support,也就是为futex添加pi算法解决优先级逆转的能力,使用pi-support的futex又称为pi-futex.在linux内核的同步机制中,有一个pi算法的成例,就 ...

  4. 《Linux内核设计与实现》读书笔记(十)- 内核同步方法【转】

    转自:http://www.cnblogs.com/wang_yb/archive/2013/05/01/3052865.html 内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我 ...

  5. Linux内核同步

    Linux内核剖析 之 内核同步 主要内容 1.内核请求何时以交错(interleave)的方式执行以及交错程度如何. 2.内核所实现的基本同步机制. 3.通常情况下如何使用内核提供的同步机制. 内核 ...

  6. 初探内核之《Linux内核设计与实现》笔记上

    内核简介  本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效 ...

  7. Linux 内核协议栈 学习资料

    终极资料 1.<Understanding Linux Network Internals> 2.<TCP/IP Architecture, Design and Implement ...

  8. linux内核同步之每CPU变量、原子操作、内存屏障、自旋锁【转】

    转自:http://blog.csdn.net/goodluckwhh/article/details/9005585 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 一每 ...

  9. Linux内核中锁机制之完成量、互斥量

    在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...

随机推荐

  1. [原创]ASM动态修改JAVA函数之函数字节码初探

    ASM是非常强大的JAVA字节码生成和修改工具,具有性能优异.文档齐全.比较易用等优点.官方网站:http://asm.ow2.org/ 要想熟练的使用ASM,需要对java字节码有一定的了解,本文重 ...

  2. Java完成简单猜数字游戏v2.0

    猜数字游戏v2.0 优化了获取随机数.输入数据超出边界值的代码,并增加了异常处理,能够在玩家输入错误数据错误时给出可靠指引,希望对和我一样的新人有帮助, 最后希望有大神愿意帮我解决代码优化的问题,谢谢 ...

  3. iOS开发之NSTimer

    1.NSTimer叫做“定时器”,它的作用如下 Ø 在指定的时间执行指定的任务 Ø 每隔一段时间执行指定的任务 2.调用NSTimer下面的方法就会开启一个定时任务 + (NSTimer *)sche ...

  4. unity插件开发——AssetDatabase

    AssetDatebase也是一个静态类,他的作用是管理整个工程的所有文件(一般成为“资产”).直观地说就是管理整个project窗口中的所有内容,比如,你可以增加.删除.修改文件等等. 这里有几个常 ...

  5. vue2.0自定义指令的使用方法

    感觉2.0好坑啊,自定义指令和1.0完全不一样,并且文档写得也不太清晰,下面是我写得一个demo,希望帮助大家更好地理解自定义指令 <!DOCTYPE html> <html lan ...

  6. PRINCE2的国际形势?光环国际项目管理培训

    PRINCE2的使用和应用非常广泛.在过去的12个月里,超过60,000人参加了PRINCE2基础资格(Foundation)或从业资格(Practitioner)考试.现在每周参加考试的人数超过了2 ...

  7. HTML的语义化,你需要深入了解

    有关HTML的一些基础课程,很多网站都有讲,于我而言,真正实践起来,我只要求我能够让它表现出我所想要的结果即可.然而,这种要求,对于后期的维护与测试,真的是......想起日前我们所做的这个项目,那里 ...

  8. 原型链、prototype、_proto_那些事

    一.概念 1.Prototype:每一个构造函数都有一个原型对象,这个对象就是Prototype.这个构造函数如何找到他的原型对象呢?每个构造函数都会有一个prototype属性,指向它的原型对象. ...

  9. 这辈子只能碰到一次! 记一次SSL无故被撤消!

    SSL证书刚更新一切都那么正常, 突然有一天网站不能访问了, Chrome浏览器提示有风险, 没有继续访问链接,没有,没有, 重要的事情说三遍, 于是乎赶紧加班查原因, 发展浏览器报的错误是证书撤消( ...

  10. es6 module + webpack

    其实在之前本人就看了 es6 里面的一部分内容,当然是阮一峰大神的 ECMAScript 6 入门. 最近闲来无事又来看下,其中 Module 的语法 这章时候,用里面代码跑的时候,理所当然的报错 S ...