一、信号量简介
信号量和之间的进程间的通信(命名管道,匿名管道、消息队列)不同,它不是用来传递数据的,它是一个计数器,用在多个进程提供对共享数据对象的访问,使得资源在一个时刻只有一个进程或者线程所拥有。那么共享内存的访问就存在了两种问题,一种是互斥的访问,一种是同步的访问。
在介绍同步和互斥的操作的之前,我们来介绍一下临界区和临界资源的概念。
- 临界资源:同一时刻只能被一个进程同时使用,也就是不可被多个进程所共享。
- 临界区:是一段涉及到了互斥资源的程序代码段,即用锁加上的部分。
因此这个我们对于这个临界资源的访问便有了同步访问和互斥访问两种方式。
- 同步:同步就是每个进程对这个资源的占用是有先后顺序的
- 互斥:互斥访问不可共享临界资源。
二、信号量的含义
可以说信号量是一种特殊的变量,程序对于信号量的访问都是原子操作,且只允许它进行等待和发送操作。
struct semaphore
{
int value;
pointer_PCB queue;
}
信号量被定义为含有一个整型数据的结构体,其整型值可以大于小于和等于0,他们分别又代表了不同的含义。
- 大于0:表示可提供给进程使用的资源个数
- 小于0:表示其等待队列中正在等待使用临界资源的进程数目
- 等于0:表示没有临界资源可供使用同时没有等待的进程
信号量是有初值的,一旦当我们申请使用信号量,我们则通过P操作对信号量进行减一的操作,一旦当我们的信号量减到0的时候就表示我们没有资源了,其他进程如果想要访问这个临界资源就必须等待,当这个正在拿到临界资源的进程执行完毕,就要执行V操作来对信号进行增加1的操作。
三、PV操作
(1)PV操作的含义
信号量的值是可以进行更改的,也只能由P和V操作来访问,同时P、V操作在执行的过程中不可中断
因此我们可以对之前的同步和互斥的定义再做一个说明:
- 互斥:P、V操作在同一个进程中
- 同步:P、V操作不再同一个进程中
(2)P操作
P操作表示申请一个资源,因此要将该信号量的值减去1,如果结果小于0,则调用P操作的进程就进入等待该资源的阻塞队列中。
(3)V操作
V操作表示释放一个资源,因此要将该信号量的值加上1,如果结果不大于0,则从该资源的阻塞队列的首部唤醒一个进程插入就绪队列中。
四、Linux下信号量机制
(1)创建或取得信号量
可以用来控制多个信号量。它是非原子操作。
在system V版本的信号量创建的时候有缺点,是因为由于我们创建的信号还没设置为分开的,此时如果是两个进程,一个进程用来创建,一个进程用来设置,这个时候就会出现错误。
函数原型
int semget(key_t key, int nsems, int semflg);
头文件:
<sys/sem.h>
参数:
- key:是一个整数,并且唯一且非零,其他的进程可以通过它访问一个信号量。
- nsems:指的是创造出几个信号量,可以选择一个,如果选择多个,则是信号量集
- semflg:是一组标记