在上一篇博文中笔者分析了关于内存屏障、读写自旋锁以及顺序锁的相关内容,本篇博文将着重讨论有关信号量、读写信号量的内容。

六、信号量

关于信号量的内容,实际上它是与自旋锁类似的概念,只有得到信号量的进程才能执行临界区的代码;不同的是获取不到信号量时,进程不会原地打转而是进入休眠等待状态。它的定义是include\linux\semaphore.h文件中,结构体如图6.1所示。其中的count变量是计数作用,通过使用lock变量实现对count变量的保护,而wait_list则是对申请信号量的进程维护的等待队列。

图6.1      信号量的结构体定义

我们首先看下它是如何使用的,首先定义一个信号量,然后初始化信号量,它包括两种方法。如图6.2所示。方法1:简单的初始化,定义信号量的个数由val决定,实际上val值即是赋给信号量结构体中的count变量;方法2是直接将结构体中count值设置成1,此时信号量可用于实现进程间的互斥量。注意:对于信号量的初始化函数Linux最新版本存在变化,本文所采用的Linux版本已不存在如init_MUTEX和init_MUTEX_LOCKED等初始化函数,同时也更换了名字等,这点读者在阅读的时候需要下,因此笔者建议以后在编程中遇到需要使用信号量的时候尽量采用sema_init(struct semaphore *sem, int val)函数,因为这个函数就目前为止从未发生变化。

图6.2      信号量的初始函数

下面我们讨论如何获得信号量,它主要包括三个函数,第一个函数表示当信号申请不到时会进程会休眠;对于第二个函数来说,它表示如果当进程因申请不到信号量而进入睡眠后,能被信号打断,这里所说的信号是指进程间通信的信号,比如我们的Ctrl+C,但这时候这个函数的返回值不为0;第三个函数表示信号量无论是否获得,都将立即返回,但返回值会根据是否申请成功而定,同时这个函数也不会导致睡眠。最后的up函数,这个还是很好理解的,就是释放信号量,进而唤醒队列中的等待信号量的进程。函数如图6.3所展示一般。

图6.3      信号量的获得和释放函数

接下来笔者将举几个例子,依次如图6.4,图6.5所示。图6.4的例子仍是实现一个设备只能被一个进程打开。例子很简单,这里便不再细说,主要体现到底如何使用信号量。如图6.4所展示。

图6.4      信号量的使用示例

如图6.5实现的是进程间的同步问题。实际上,当把信号量的初始值为0,则可以实现同步了。正如图6.5所展示一般,对于执行单元A而言,如果执行单元B不执行up函数,执行单元A就因为申请不到进程而睡眠,直至up函数被调用,所以执行代码b前必须等到执行单元B执行完代码c。相信这个内容在操作系统课程都均有提及。

图6.5      信号量实现同步示例

讨论过示例后,相信读者对于信号量的使用有了比较好的了解。下面让我们来简单的讨论下它的实现机制。通过了解信号量的结构体,可以发现结构体中除了使用自旋锁机制外,就是count值的变化(这一点先前已提及)。它的源码如图6.6,图6.7所示。

图6.6  信号量down函数内核源码图6.7  信号量up函数内核源码

从源码中可以看到信号量利用自旋锁的相关函数实现了对count变量的保护,通过判断变量是否大于0以及自增减来实现信号量的申请和释放。也是因为这一点,所以信号量能够实现同步机制。

另外,关于源码中的__down和__up函数的实现内容,它们其实是维护申请信号量的进程的链表队列(增加、删除操作),以及进程调度方面的一些信息(超时机制),从而让进程实现休眠。由于其中的源码量较为庞大,涉及的内容也较多,故这里不再深入讨论,感兴趣的可以查阅相关资料。

关于信号量的内容还有一点需要提及,我们知道信号量时进程级的,因此对于它的使用必然是当占用资源较长时间的时候。这点在使用信号量的使用需要重点考虑,反之,则容易影响程序的性能等。OK,至此,关于信号量的内容即讨论到此。

七、读写信号量

接下来笔者将讨论有关读写信号量的内容,这部分是较难的一部分,需分析较多的源码。同样,我们首先看下它主要能够做些什么:读写信号量与信号量的关系如同自旋锁与读写自旋锁的关系,它允许N个读操作同时访问共享资源,但最多只能有一个写操作。它的定义位置是在arch\x86\include\asm\rwsem.h以及kernel\rwsem.c中。关于它的结构体的定义,如图7.1所示。显然,它的结构体定义和信号量的结构体定义如出一辙。

图7.1      读写信号量的结构体实现

而后了解下它的具体使用方法,如图7.2所展示的函数。同其它锁机制类似,它所提供的接口函数也是较为简单,包括这些函数能实现的功能都差不了多少。

图7.2      读写信号量的接口函数

在了解读写信号量的定义和使用后,接下来读者将讨论的具体源码实现。它的具体实现是采用汇编实现,比较绕,需配合源码来一一说明,源码次序依次如图7.3至图7.8所示。为便于分析,下面源码只给出最为关键的内容。

对于图7.3所展示的内容主要是读写信号量中需要使用的一些宏定义,具体为何取这个值笔者就不大了解了,后续研究深入了可能会有所体会。

图7.3      读写自旋锁的内核源码

图7.4      读写自旋锁的内核源码

图7.5      读写自旋锁的内核源码

图7.4和同7.5所示源码主要体现了读锁和写锁的实现内容。实际上还是利用test指令检测count变量的值来实现。申请成功的内容好理解,其中的xadd指令表示将原操作数和目的操作数值相交换,而后相加保存入目的操作数。一旦读写信号量申请失败,则需要跳转到如图7.6,图7.7所示的源码中。其中图7.6,图7.7中所示的源码没多少内容,最后还是跳转到rwsem_down_read_failed和rwsem_down_write_failed函数中,通过汇编源码保存改变相应存储变量的寄存器,从而再次返回到C代码中,如图7.8所示的源码中。由于笔者能力有限,对于图7.8所示的源码内容中调用的rwsem_down_write_failed函数被没有研究透,故这里并未进一步深入研究。

至此,关于读写信号量的内容讨论基本结束,确实由于笔者能力有限,关于读写信号量的内容以及本博文的系列内容,读者可进一步深入研究,并欢迎讨论。共同进步。

图7.6  读写自旋锁的内核源码图7.7  读写自旋锁的内核源码

图7.8      读写自旋锁的内核源码

出于文章篇幅的限制,本篇博文到此结束,后续将会给出《大话Linux内核中锁机制之完成量、互斥量》,感兴趣的读者可继续阅读后一篇博文。由于笔者水平所限,博文中难免有出错之处,欢迎读者指出,大家相互讨论,共同进步。

来源:oschina

链接:https://my.oschina.net/u/4280386/blog/4238578

linux 信号量锁 内核,Linux内核中锁机制之信号量、读写信号量相关推荐

  1. oracle 几种锁,oracle_基于oracle中锁的深入理解,ORACLE里锁有以下几种模式:0:no - phpStudy...

    基于oracle中锁的深入理解 ORACLE里锁有以下几种模式:0:none 1:null 空 2:Row-S 行共享(RS):共享表锁 3:Row-X 行专用(RX):用于行的修改 4:Share ...

  2. qt linux excel文件读取显示,qt中写入excle?QT怎样读写excel-CSDN论坛

    如何通过Qt 创建一个excel文件 首先,我们打开前文所的工目. 然后,我们在界面设计,加入一个label用于显示,要保存的目录.注意设置下相应的界面布局. 然后,我们在mainwindow.h类中 ...

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

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

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

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

  5. Linux内核信号量:二值信号量/互斥信号量,计数信号量,读写信号量

    <semaphore信号量:一个简单的示例程序>用户态程序 目录 概念 应用场景 使用方法 内核信号量的构成 信号量的API 初始化 PV操作 获取信号量(P) 释放内核信号量(V) 补充 ...

  6. Linux信号量(3)-内核信号量

    概念 Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干. 如果有一个任务想要获 ...

  7. 【Linux 内核 内存管理】RCU 机制 ① ( RCU 机制简介 | RCU 机制的优势与弊端 | RCU 机制的链表应用场景 )

    文章目录 一.RCU 机制 二.RCU 机制的优势与弊端 三.RCU 机制的链表应用场景 一.RCU 机制 RCU , 英文全称是 " Read-Copy-Update " , 对 ...

  8. 内核同步机制-读写信号量(rw_semaphore)

    四.读写信号量(rw_semaphore) 读/写信号量适于在读多写少的情况下使用.如果一个任务需要读和写操作时,它将被看作写者,在不需要写操作的情况下可降级为读者.任意多个读者可同时拥有一个读/写信 ...

  9. 原子操作、信号量、读写信号量和自旋锁

    本系列文章分两部分,第一部分详细地介绍了 Linux 内核中的同步机制:原子操作.信号量.读写信号量和自旋锁的API,使用要求以及一些典型示例.第二部分将详细介绍在Linux内核中的另外一些同步机制, ...

最新文章

  1. JS的数据访问及优化访问速度
  2. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170318
  3. 混合多云每个人都应避免的3个陷阱(第2部分)
  4. UDP聊天工具的实现
  5. 一个完整的使用的例子,和可下代码
  6. Linux教程:10条秘诀确保Linux桌面安全性
  7. SQL Server2005完全版与精简版的一个差别(抄录)
  8. 探索Android FrameWork底层开发视频全套
  9. php连接mssql的一些相关经验和总结
  10. [办公自动化]目录修改以及插入分页符后行间距自动变宽
  11. operator开发流程
  12. yolov5检测限定长宽比检测范围的目标
  13. 17.12.2B组总结
  14. 钉钉发布会发了个“ / ”,还说这玩意能替我们上班?
  15. Java中ArrayList的练习
  16. job全异常 mapreduce_eclipse 运行MapReduce程序错误异常汇总(解决Map not fount)
  17. Django项目实战——7—(openid是否绑定用户的处理、用户基本信息渲染、添加和验证邮箱)
  18. easypoi导出word文档,字段是空值、null导出空白到模板
  19. Horizon Daas TA设备FDB 或 EDB 数据不一致问题
  20. 吴洪声十问CSDN蒋涛:年过35 岁,程序员们都去哪儿了?

热门文章

  1. 三 s5p4418对mcp2515 can总线的支持
  2. ELK 企业级日志分析系统
  3. HD2500显卡驱动linux,Intel发布HD Graphics 2500/4000显卡Win10驱动下载
  4. 函数 单片机glint_GL 库函数
  5. oracle不开归档对效率会快吗,关于性能:存档庞大的数据库(oracle),而不会影响向其插入记录的进程...
  6. mysql function_MySQL里event_ scheduler导致复制中断的故障分析-爱可生
  7. 优酷复制的html代码怎么用,关于网页上增加视频功能的代码
  8. android 两端对齐,LinearLayout子控件两端对齐
  9. java调用net webservice_java调用.net的webservice
  10. 一份不大的救命文档,一场时间与生死的接力