首页 » Linux » 进程间通信——信号量

进程间通信——信号量

原文 http://blog.csdn.net/DY_1024/article/details/79203079

2018-01-31 02:01:45阅读(215)

进程间通信——信号
开始:

之前我有在博客中写到进程间通信的方式:管道和消息队列 详情可以参考这两个链接:进程间通信—管道 和 进程间通信—消息队列 今天我总结一下进程间通信的另一种方式:信号量。

信号量本质是一种数据操作锁,信号量本身是不具有数据交换功能的,而是通过控制其他的资源来实现进程间通信的, 它本身是一种资源的标识,也可以当作是资源的计数器,信号量在进程通信的过程中负责数据操作的互斥和同步。如果把信号量看作计数器的话,那么他标识的就是当前两个进程所访问空间的自愿的数目。

 当这个计数器的值要么是0,要么是1的时候,我们就叫这个信号量为二元信号量。 信号量本身其实也是一种资源,所以作为信号量就必须保证,要被两个进程看见。

对于信号量有两种操作:P和V。  

P操作:对整数进行减减,本质就是将信号量掌管的资源交给申请者;

V操作:对整数进行加加,本质就是申请者把资源进行归还。

 举个例子:假如信号量掌管的资源是一间教室,信号量初始值我们设置为1,此时当有学生(也就是进程)来申请这块资源(也就是教室),此时对信号量执行P操作,信号量的值被P操作进行了减减,值为0,若刚好此时又有另外一个学生(也就是新的进程)来申请教室(也就是资源),此时因为信号量的值为0,则申请失败,当前一个学生(也就是进程)对信号量执行V操作也就是对信号量进行加加,其本质是把资源进行归还,此时信号量的值变成1,新的学生(也就是新的进程)就可以申请资源了,就继续对信号量执行P操作,这个过程就是使用信号量进行进程间通信。

 为什么我们要使用信号量呢?  为了防止因多个程序同时访问一块临界资源而引起的问题,此时我们需要一种方法,使得能够在任意时刻只有一种进程访问临界资源,而信号量就可以提供这种机制,让一个临界资源同时只有一个进程在访问,也就是说:信号量用来调谐进程对共享资源的访问。

 信号量的工作原理?  由于二元信号量只能进行两种操作:P和V操作;

 P(sv):如果sv的值大于0,就给他减一,如果等于0,就挂起该进程  

V(sv):如果有进程因为等待sv而挂起,此时就让他恢复运行,如果没有进程被挂起,就让sv加一。 

用书面化的语言来描述刚才举的借教室的例子就是这样:两个进程共享信号量sv,当第一个进程执行P操作,他将得到信号量资源,此时使得sv减1,而第二个进程将被阻止进入临界区,因为当第二个进程试图进行P操作时,此时sv==0他就会被挂起,直到前一个进程离开临界区并执行V操作,释放信号量,这时候第二个进程才会被执行。 

信号量的周期和消息队列一样,是随内核的。 使用代码来创建信号量: ①将实现的接口:封装在comm.h中,创建test_sem.c,在test_sem.c里面创建子进程,父子进程都往标准输出打印 ②父进程打印“A”、“A ”。子进程打印“B”、“B ”,此时临界资源就是stdout( 标准输出) ③若没有实现信号量控制,那么我们在stdout看到的就是乱序的,如经过信号量的控制,在屏幕看到的就是有序的。 首先我们来实现出头文件里面的接口,包括创建,获取,P/V操作,销毁等操作;

 在实现之前,我们来学习几个接口的使用: 创建信号量函数:int semget(key_t key, int nsems, int semflg); 返回值:使用man 手册查看返回值,如下:
进程间通信——信号量

如果成功就返回信号集的标识符,所以我们创建的是一个信号量的集合,之前我们所说的信号量是有所偏差的,只是为了方便理解和学习,所以返回值:成功返回这个信号量标识符,失败返回1;

 key:使用ftok函数创建,ftok函数的返回值,之前在消息队列博客中,创建消息队列中有学习,链接:进程间通信—消息队列

 nsems:刚才知道信号是一个集合,那么创建的时候就要知道创建集合的大小,nsems就是大小

 semflg:当值传“IPC_CREAT”的时候,创建一个信号量集合,如果创建的信号量集合已经存在,就把存在的信号量的标识符返回;如果值传“IPC_CREAT|IPC_EXCL”,创建一个信号量集合,如果创建的信号量已经存在,就会报错

 操作信号量集函数:semctl(int semid, int semnum, int cmd, ...) 

返回值:失败返回-1;

 semid: 信号量集标识符 semnum:既然信号有集合,那么要操作信号量,就要有对应的下标,semnum就是下标 cmd:对应的操作,比如:IPC_RMID 、IPC_SET、IPC_STAT 进行P/V操作信号集的函数:int semop(int semid, struct sembuf *sops, unsigned nsops) 

返回值:成功返回0,失败返回-1; 

semid:信号集标识符 

sops:struct sembuf结构体指针,man手册解释如下:  

结构体里面:sem_num:对应信号的下标    

sem_op:信号对应的操作,p 或者 v    

sem_flg:如果把改成员设置成“SEM_UNDO”,此时,当进程进入临界资源区执行了P操作,但是在没有执行V操作之前,就异常结束了,此时还有其他进程在等待进入资源区,但是无法访问临界资源,这个时候,就造成了死锁,但是如果把sem_flg设置成SEM_UNDO,那么当访问进程异常结束的时候,就会把信号恢复到初始值,防止死锁,这个动作叫做:回滚
进程间通信——信号量

 nsops:信号集的个数以上就是在信号量有关操作需要知道的接口。
sem.h:

最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹