菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
176
0

IPC-信号量

原创
05/13 14:22
阅读数 29281

IPC-信号量

1、参考文章:https://www.cnblogs.com/melons/p/5791796.html

https://www.cnblogs.com/52php/p/5851570.html

信号量绝对不同于信号,一定要分清,关于信号,参考上一篇博客

一、信号量定义

1、信号量的本质是一种数据操作锁,它不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。


2、当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态(进程挂起等待)直至资源可用。 当进程不再使用一个信号量控制的共享资源时,信号量的值+1(信号量的值大于0),对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。 而在信号量的创建及初始化上,不能保证操作均为原子性。

1.1、知识点

1、临界资源:同一时刻,只允许一个或有限个进程或线程访问的资源。
2、临界区:访问临界资源的代码段。
3、原子操作:不可被分割或中断的操作,操作一旦开始执行,就比执行结束,中途不能被任何原因打断。
4、进程的同步:多个进程需要相互配合才能完成一项任务,比如1件事情A进程先做前半部分,B进程做后半部分。通过信号量可以达到,AB先后的顺序,从而保证一起配合完成本件事情。同步的宏观概念,但具体下面的实现是用信号量这种互斥机制完成的。
5、进程的互斥:由于各个进程都要访问共享资源,而且这些资源不能被同时访问,因此各个进程间需要竞争使用这些资源,我们将这种关系称为进程的互斥。

1.2、信号量举例

(1)多个人同时用一个笔签字,此时只能有一个人用笔写字,其他人只有等他写完才可以使用这支笔。
(2)若商场试衣间可以有3个试衣间,可以同时供3个人使用,其他人必须等到其中的试衣间没人才能使用。
(3)但是像走廊,不是临界资源,可以同时由多人同时通行。

二、信号量工作原理

2.1、为何使用信号量

为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法, 它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。 临界区域是指执行数据更新的代码需要独占式地执行(这个房子暂时我一个人可以用, 房子好比临界区域)。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程对共享资源的访问的。其中共享内存的使用就要用到信号量。

2.2、信号量原理

信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行。
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂 起,就给它加1.

举个例子,就是两个进程共享信号量sv,且sv初始信号值为1,一旦其中一个进程执行了P(sv)操作,它将得到信号 量,并可以进入临界区,使sv减1。

而第二个进程将被阻止进入临界区,因为当它试图执行 P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时 第二个进程就可以恢复执行。

三、Linux信号量API

Linux提供了一组信号量接口来对信号进行操作,声明在头文件sys/sem.h中。

3.1、int semget(key_t key, int num_sems, int sem_flags);

//函数功能:创建一个新信号量或取得一个已有信号量,原型为:

[key]:数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget()函数并提供一个键,再由系统生成一个相应的信号标识符(semget()函数的返回值),只有semget()函数才直接使用信号量键,所有其他的信号量函数使用由semget()函数返回的信号量标识符。

[num_sems]:指定需要的信号量数目,它的值几乎总是1。

[sem_flags]
1、当想要当信号量不存在时创建一个新的信号量,可以用权限制和IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,如果给出的键对应的信号量不存在,则创建新的信号量,否则不创建,仅仅是打开这个已有的信号量并返回标识,不会产生错误。
2、IPC_CREAT | IPC_EXCL则完全创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

[return] :数成功返回一个相应信号标识符(非零),失败返回-1.

3.2、int semctl(int sem_id, int sem_num, int command, ...);

//函数功能:设置、获取、删除信号量

[sem_id] : 信号量标识符,由semget函数返回。

[sem_num] : 信号量下标,从0开始。(可以理解为信号量数组,因为semget创建信号量时,可以一次性创建多个,sem_num与semget创建几个有关)

[command] : 信号量执行的操作类型: 设置SETVAL、获取GETVAL、删除IPC_RMID

[union semun *] :联合体类型的可省略参数
	union semun
	{
	    int val;   //仅使用该成员即可。
	    struct semid_ds *buf;
	    usigned short *array;
	}

//函数使用说明
union semun Test;
Test.val =  1;
unsigned char ucRdSemVal;
semctl(semid,0,SETVAL,Test)	//设置信号量
ucRdSemVal = semctl(semid,0,SETVAL)		//获取信号量
semctl(semid,0,IPC_RMID)	//删除信号量

3.3、int semop(int sem_id, struct sembuf *sem_ops,size_t num_sem_ops);

//函数功能:对信号量进行PV操作,V(+1)、P(-1)
sem_id:信号量的id,用作标识。 
sem_ops:指向一个结果体`数组`的指针,每个数组元素至少包含以下几个成员:
struct sembuf
{
    short sem_num;  //信号量的下标,从0开始。
    short sem_op;  //信号量一次操作总需要改变的数值,+1是v操作,-1是p操作,
    short sem_flg;
/*sem_flg通常设置为SEM_UNDO:表示操作系统会跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量,防止其他进程一直处于等待状态。*/  
}
num_sem_ops:指的是结构数组的元素个数。


//函数使用说明
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
int semop(semid, struct sembuf *sops,1);	//P操作
buf.sem_op = 1;
int semop(semid, struct sembuf *sops,1);	//V操作

四、编程示例

1、父子进程
https://blog.csdn.net/mignatian/article/details/80019399

https://blog.csdn.net/Shawei_/article/details/81302876
2、同一个进程双开
https://www.cnblogs.com/ladawn/p/8870014.html

http://www.cnblogs.com/xcywt/p/5199216.html
2、不同进程访问争夺同一个资源
https://blog.csdn.net/yishizuofei/article/details/78318967

发表评论

0/200
176 点赞
0 评论
收藏
为你推荐 换一批