信号量通信之semget()、semctl()、semop()及其基础实验
这个信号量理解起来是有点不容易啊,我看书看了好几遍才知道怎么回事。在讲这一节信号量之前,我还 是想先说几个小知识点,这也是我在学习完后最终理解的“精华”,哈哈!
信号量是干啥的?
信号量就是用来解决进程间的同步与互斥问题的一种进程间通信机制。
同步与互斥的通俗理解
这两个名词咱们从字面上就能理解。举个例子吧,在创建子进程时,你是怎么保证父子进程执行的先后顺序呢 ?我在以前的时候是通过sleep()函数来实现的,比如我想让子进程先运行再让父进程运行,那么我就在父进 程的程序中加一个sleep()函数,让父进程先睡眠,这样子就能先执行子进程了。有的时候咱们事先无法知道 父进程和子进程哪一个先执行,但是要向我那样使用sleep()函数,只能保证先执行子进程,但是不能保证子 进程执行完后再执行父进程,这样说能理解吧。所以如果我们想要子进程完全执行完后再执行父进程,就可以 利用信号量来解决它们之间的同步问题。还不理解也没关系,我会在后面的实验中再结合实际讲。再举个更通 俗的例子,一条食品生产线上,假设A、B共同完成一个食品的包装任务,A负责将食品放到盒子里,B和C负责 将盒子打包。必须得是A先装食品B再打包吧,要是B不按规则先打包,那A还装啥,所以就需要一种机制方法保 证A先进行B再进行,“信号量”就是这种机制方法,AB之间的关系就是同步关系;再假设打包要用到刀子,而 车间就有一把刀子,这时候B和C就构成了互斥关系。
信号量与信号的区别
不瞒你说,我刚开始 学的时候所理解的就是“信号量是很多个信号”,当然这是错误的哈!光从英语上看就不一样:信号量是 Semaphore,而信号是 Signal 。其实,信号和信号量是不同的。它们虽然都可以实现同步和互斥,但是前者 是使用信号处理器来进行的,而后者是使用P,V操作来实现的。(PV操作后边有讲)
好了,进入正题。
信号量概述
在多任务操作系统环境下,多个进程会同时运行,并且一些进程间可能会存在一定 的关联。多个进程可能为了完成同一个任务相互协作,这就形成了进程间的同步关系。而且在不同进程间,为 了争夺有限的系统资源(硬件或软件资源)会进入竞争状态,这就是进程间的互斥关系。
进程间的互 斥关系与同步关系存在的根源在于临界资源。临界资源是在同一时刻只允许有限个(通常只有一个)进程可以 访问(读)或修改(写)的资源,通常包括硬件资源(处理器、内存、存储器及其它外围设备等)和软件资源 (共享代码段、共享结构和变量等)。访问临界资源的代码叫做临界区,临界区本身也会称为临界资源。
信号量是用来解决进程间的同步与互斥问题的一种进程间通信机制,包括一个称为信号量的变量和在 该信号量下等待资源的进程等待队列,以及对信号量进行的两个原子操作(P/V操作)。其中,信号量对应于 某一种资源,取一个非负的整形值。信号量值(常用sem_id表示)指的是当前可用的该资源的数量,若等于0 则意味着目前没有可用的资源。
PV原子操作(很重要的)
PV原子操作的具体定义如下:(好好 理解,很重要的啊)
● P操作:如果有可用的资源(信号量值>0),则此操作所在的进程占 用一个资源(此时信号量值减1,进入临界区代码);如果没有可用的资源(信号量值=0),则此操作所在的进程 被阻塞直到系统将资源分配给该进程(进入等待队列,一直等到资源轮到该进程)。
● V操作 :如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞进程;如果没有进程等待它,则释放一个 资源(即信号量值加1)。
常见的使用信号量访问临界区的伪代码如下图1:
图1中的非临界 区和临界区在咱们这里就是代码,具体这张图的理解还要结合着后面的实验才能理解。
最简单的信号 量只能取0和1值,这种信号量叫做二维信号量,在本节中,主要讨论二维信号量。二维信号量学好了,比较容 易扩展到使用多维信号量的情况。