在上一篇博文中笔者分析了关于信号量、读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题。

八、完成量

下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等待另一个执行单元完成某事后方可执行,它是一种轻量级机制。事实上,它即是为了完成进程间的同步而设计的,故而仅仅提供了代替同步信号量的一种解决方法,初值被初始化为0。它在include\linux\completion.h定义。

如图8.1所示,对于执行单元A而言,如果执行单元B不执行complete函数,执行单元A就会因为申请不到进程而睡眠,直至complete函数在执行单元B中被调用,所以执行代码b前必须等到执行单元B执行完代码c。这一点同信号量同步的机制类似,只是调用的函数不同而已。

图8.1      完成量的使用示例

下面笔者将讨论下它的实现机制。笔者从内核中找出了相关的源码,依次如下图8.2至图8.5所示。由于图8.5中的do_wait_for_common函数实现较多,故给出的是删节后的函数大概框架图。

图8.2      完成量的结构体定义

图8.2展示了完成量的结构体定义,done变量是完成量要保护的对象,wait则是申请完成量的进程的等待队列。从图8.3中我们可以看出当初始化完成量变量时,done变量被初始化成0,对比利用信号量实现同步的内容,可以发现它们是相一致的。

图8.3      完成量的内核源码

配合图8.1中的完成量源码,我们发现现在对于执行单元A,它现在执行完代码a后调用wait_for_common函数,这个函数的源码实现如图8.5所示。可以看出,它其实即是对done变量作判断,若done变量没有大于0,则它一直处于while循环中。此时,若是执行单元B执行完代码c后,执行complete函数,此时,观察图8.4中的complete函数实现,可以发现它对done变量值增1。此时,wait_for_common函数便会退出while循环,同时将done值减1,以表示申请完成量成功。


图8.4      完成量的内核源码

图8.5      完成量的内核源码

至此,关于完成量的内容即讨论到此,总体来说,完成量的内容还是较为简单的。后续笔者将会讨论有关互斥量的使用和实现。

九、互斥量

下面笔者将讨论互斥量的相关内容。首先互斥量的提出主要是由于进程在使用信号量后开销较大。互斥量提供了两种机制,包括经典互斥量和实时互斥量两种,依次在文件include\linux\mutex.h (经典互斥量)和include\linux\rtmutex.h (实时互斥量)中定义,下面我们来看下它的一些具体内容。

首先讨论关于经典互斥量的内容,它的结构体定义如图9.1所示。结构体中我们重点关注count、wait_lock、wait_list等变量。和读写信号量的定义相类似。

图9.1      经典互斥量的结构体定义

另外,关于它的用法和先前的一些锁机制其实都差不多,具体函数即把加解锁的函数换成mutex_lock和mutex_unlock等,而它的内部的源码实现是建立上原子锁和自旋锁的相关机制之上,同时还有一些关于队列维护的一些内容,这些内容,我们可从它的结构体定义即可简单看出,这里不太深入讨论了,感兴趣的话可以看上面提示的两个文件。

下面我们来介绍实时互斥锁的内容,在介绍这个内容之前,我们先来看一个有趣的问题,就是无限制优先级反转问题,这个问题曾经引起了美国的火星探测器的故障(后续介绍)。

下面具体讨论到底什么是无限制优先级反转问题,总体来说,图9.2至图9.7展示了整个问题发生的过程。首先当前有一个执行单元C获取了一个互斥量,正在所保护的临界区中执行,且不打算在短时间内推出。此时,系统中“跑来”执行单元A申请这个互斥量,由于执行单元C正在使用这个互斥量,故A只能等待C执行完,尽管A的优先级远高于C(多么无奈)。这时候,又冒出一个执行单元B,它的优先级介于A和C之间。由于系统的一个中断的发生,导致执行单元B直接抢占C进程而开始执行互斥量所在的临界区。但这种情况实际上也抢占了执行单元A,尽管执行单元A的优先级高于执行单元B(A就是个悲剧)。如果执行单元B继续执行,那么执行单元A将等待更长的时间,因为执行单元C被执行单元B抢占,所以它也只能等待执行单元B完成其操作。因此看起来就像执行单元B的优先级高于执行单元A一样。这种情况就是我们所说的无限制优先级反转问题。

图9.2  执行单元C访问临界区                                         图9.3  执行单元A等待C完成其操作

图9.4  B抢占C而执行临界区                                              图9.5  B在临界区中执行

图9.6  B执行完后C继续执行临界区                                      图9.7  A最终执行临界区

下面简单提及下美国火星探测器的故障问题:1997年的美国的火星探测器(探测器使用的是Vxworks系统)遇到一个优先级反转问题引起的故障。首先火星探测器有一个信息总线,有一个高优先级的总线任务负责总线数据的存取,访问总线都需要通过一个互斥锁(共享资源出现了);还有一个低优先级的,运行不是很频繁的气象搜集任务,它需要对总线写数据,也就同样需要访问互斥锁;最后还有一个中优先级的通信任务,它的运行时间比较长。平常这个系统运行毫无问题,但是有一天,在气象任务获得互斥锁往总线写数据的时候,一个中断发生导致通信任务被调度就绪,通信任务抢占了低优先级的气象任务,而无巧不成书的是,此时高优先级的总线任务正在等待气象任务写完数据归还互斥锁,但是由于通信任务抢占了CPU并且运行时间比较长,导致气象任务得不到CPU时间也无法释放互斥锁,从而使本来是高优先级的总线任务也无法执行,总线任务无法及时执行的后果被探路者认为是一个严重错误,最后就是整个系统被重启。事实上,Vxworks系统允许优先级继承,然而遗憾的是工程师们将这个功能给停止了,从而使火星探测器就此悲剧了。

由于无限制优先级反转问题无法使用经典互斥量来解决,理由是经典互斥量中的队列并没有实现将等待进程按优先级排队。实时互斥量就此因运而生,我们们可以简单看下它的结构体定义,如图9.8所示。

图9.8      实时互斥量的结构体定义

既然经典互斥量不能解决将等待进程按优先级排队问题,因此对于实时互斥量,它的实现关键即是wait_list的实现,看此变量的定义类型为plist_head,便可一目了然。在plist_head链表操作数,它即采用了优先级继承关系将等待进程队列按进程优先级方式排队。这里优先级继承表示为如果高优先级的进程阻塞在互斥量上,该互斥量当前由低互斥量拥有,那么将低优先级的临时提升到高优先级。

至此,关于互斥量的内容即讨论到此,经过上述的讨论,相信读者对于互斥量的内容有了比较好的了解,后续《大话Linux内核中锁机制之RCU、大内核锁》将会重点给出有关RCU机制的相关分析,感兴趣的读者可继续阅读后一篇博文。由于笔者水平所限,博文中难免有出错之处,欢迎读者指出,大家相互讨论,共同进步。

转载于:https://www.cnblogs.com/alantu2018/p/8459355.html

Linux内核中锁机制之完成量、互斥量相关推荐

  1. linux 信号量锁 内核,Linux内核中锁机制之信号量、读写信号量

    在上一篇博文中笔者分析了关于内存屏障.读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量.读写信号量的内容. 六.信号量 关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程 ...

  2. 大话Linux内核中锁机制之原子操作、自旋锁【转】

    转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...

  3. linux内核中锁有哪些,Linux内核中有哪些锁

    Linux内核中的各种锁 在LInux操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需 ...

  4. Linux 内核的锁机制

    概要: 锁机制是一种保护共享资源不被多次访问的一种机制.共享资源可以是数据(如:全局变量)也可以是设备(如:GPIO). Linux锁的种类: ●互斥锁 ●自旋锁 ●信号量 本文只对前两种锁进行说明. ...

  5. Linux内核中的同步原语:自旋锁,信号量,互斥锁,读写信号量,顺序锁

    Linux内核中的同步原语 自旋锁,信号量,互斥锁,读写信号量,顺序锁 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Linux 内核中的同步原 ...

  6. 简单谈一点linux内核中套接字的bind机制--数据结构以及端口确定

    众所周知,创建一个套接字可以bind到一个特定的ip地址和端口,实际上套接字这一概念代表了TCP/IP协议栈的应用层标识,协议栈中的应用层就是通过一个ip地址和一个端口号标识的,当然这仅仅是对于TCP ...

  7. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  8. 探秘最新Linux内核中的自旋锁

    一.前言 目前最新内核中的自旋锁已经进化成queued spinlock,因此需要一篇新的自旋锁文档来跟上时代.此外,本文将不再描述基本的API和应用场景,主要的篇幅将集中在具体的自旋锁实现上.顺便说 ...

  9. Linux内核中的vfs,解析 Linux 中的 VFS 文件系统机制

    在Linux系统中,每个分区都是一个文件系统,都有自己的目录层次结构.Linux的最重要特征之一就是支持多种文件系统,这样它更加灵 活,并可以和许多其它种操作系统共存.由于系统已将Linux文件系统的 ...

最新文章

  1. 跑yolo3模型出的效果图_效果图和效果图设计到底有什么区别?区别大着呢,亲……...
  2. 【Java】ArrayList 列表的泛型
  3. Linux JDK升级
  4. ajax返回数据类型为JSON数据的处理
  5. rto净化效率计算公式_你了解废气处理设备RTO蓄热式热氧化炉的工作原理么?
  6. Centos7 -bash: ifconfig : command not found
  7. java第十版基础篇答案第九章_《Java语言程序设计》(基础篇原书第10版)第九章复习题答案...
  8. 电机控制park变换公式推导
  9. 如何在ROS中使用VScode创建功能包并编写cpp文件
  10. VB语言和C语言有什么区别
  11. matlab测量直流母线上的电压,基于模糊控制的有源滤波器直流母线电压控制
  12. JPA @PersistenceContext和@Transactional Annotation
  13. 优秀自我简介200字_个人简历自我评价200字优秀范文.doc
  14. c语言中的 t占的字节数,2017年9月计算机二级考试C语言预习自测题(4)
  15. HCIE北京考场体验报告
  16. 文件服务器拷贝资料需要解锁,如何加密U盘文件防止复制,怎样实现U盘文件防拷贝?...
  17. 在html中input是什么意思,HTML中input是什么意思
  18. xcode添加符号断点
  19. 在MTU为1500,不分片的条件下,ping包长最大为1472B的理解
  20. 暴雪、迪士尼大佬用什么画画?RayLink远控软件助力解锁远程创作

热门文章

  1. python三层架构
  2. Ubuntu 和 Redhat / Fedora 服务管理命令对比表(附Fedora16新的服务管理工具systemctl )...
  3. 【T-SQL】基础——表别名
  4. 如何破解压缩文件密码-省时省力的方法
  5. Javascript原型链
  6. Varnish purges 缓存清除
  7. Request.ServerVariables获取环境变量
  8. C语言单向链表的实现
  9. gtest使用初级指南
  10. 【FFmpeg】打印日志函数分析(可以根据不同级别打印不同颜色的日志)