进程间通信-信号量
来源:互联网 发布:unity3d入门文章 编辑:程序博客网 时间:2024/06/05 20:25
信号量:以保护进程互斥与同步为目的,本质上为计数器,记录与统计临界资源的数目。
当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用:
1.大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用;
2.当进程不再使用一个信号量控制的共享资源时,信号量的值+1(对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性)。
二原信号量:信号量的值为1或0,任一时刻只允许一个进程访问临界资源,其+-操作必须为原子操作。
信号量保护进程访问临界资源的互斥与同步,在进程申请临界资源时,先要申请信号量,所以信号量也成为临界资源。
P、V操作:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行;
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂
起,就给它加1.
Linux下信号量命令:
ipcs -s ; //查看信号量ipcrm -s <semid> //删除信号量
1.创建信号量:
函数:
int semget(key_t key,int nsems,int semflg);参数:
key:标识信号量的键值,由ftok()函数初始;
nsems:申请的信号量数目;
semflg:IPC_CREAT(单独使用,存在打开,不存在创建新的)IPC_EXCL(结合使用,不存在创建,存在返回错误码);
返回值:
返回信号量集标识符。
2.删除信号量
函数:
int semctl(int semid,int semnum,int cmd,...);参数:
semid:信号量集标识符;
semnum:信号量集中要操作的信号量下标;
cmd:删除设为IPC_IMRD;
... :可变参数列表,此处设为NULL;
返回值:
<0,失败,==0,成功删除。
3.信号量初始化:
函数:
int semctl(int semid,int semnum,int cmd,...)'参数:
semid:信号量集标识符;
semnum:信号量集中要操作的信号量下标;
cmd:此处设为SETVAL,对semnum信号量进行此控制操作;
... :可变参数设为一个联合体,如下:
union semun { int val; // 使用的值 struct semid_ds *buf; // IPC_STAT、IPC_SET 使用缓存区 unsigned short *array; // GETALL,、SETALL 使用的数组 struct seminfo *__buf; // IPC_INFO(Linux特有) 使用缓存区};将此联合中val初始化值。
4.信号量操作P()、V():
函数:
int semop(int semid,struct sembuf* sops,unsigned nsops);参数:
semid:信号量集标识符;
sops:结构体指针,结构体如下:
struct sembuf{ unsignea short sem_num; //表示在信号量集哪一个信号量上操作 short sem_op; //P操作设为-1,V操作设为1; short sem_flg; //此处代码实现设为缺省0};
初始化时初始化此结构体,并传入其地址为函数参数;
nsops:前一个参数可视为一个数组,其表示数组中元素的个数;
以上结构体成员sem_flg取值:
(1).0 (2).IPC_NOWAIT
(3).SEM_UNDO:
有一种情况:如当有两个进程同时申请一个信号量去使用临界资源时,其中第一个进程在P()操作申请以后,还没有进行V()释放操作就异常退出了,所以此时另一个进程再对此信号量进行P()操作时,因为第一个进程没有释放信号量但已经退出,此进程则会一直申请不到信号量,从而造成死锁。
解决办法:将sem_flg取值为SEM_UNDO时,它将使操作系统跟踪当前进程对信号量的修改情况,若此进程在没有释放信号量的情况下异常退出终止,它将取消先前的P()操作,使信号量恢复原值,即操作系统会自动释放该进程持有的信号量,使其它进程可以正常工作。
代码实现:模拟实现将显示器作为临界资源,若实现信号量机制父子进程则分别成对向显示器打印‘BB’‘AA’,若没有信号量,则父子进程会以无规律形式向显示器打印BA.
test_sem.c
#include "comm.h"int main(){//创建二原信号量 int semid=createSem(1);//printf("create sucess:%d\n",semid); if(initSem(semid,0,1)<0) //初始化 {perror("initSem");return -1;}pid_t id=fork();if(id==0) //child{int _semid=getSem(0); //获取信号量集 while(1){P(_semid,0); //申请信号量 printf("A");fflush(stdout);usleep(123456);printf("A");fflush(stdout);usleep(321456);V(_semid,0); //释放 }}else //father{while(1){P(semid,0); printf("B");fflush(stdout);usleep(102456);printf("B");fflush(stdout);usleep(311456);V(semid,0);}}destroySem(semid); //删除信号量集 return 0;}
comm.c
#include "comm.h"static int commSemMessage(int nums,int flags){key_t _key=ftok(PATH,PROJ_ID);if(_key<0){perror("ftok");return -1;}else{int semid=semget(_key,nums,flags); //以flag模式得到nums个信号量返回键值为_key的信号量集标识符semid if(semid<0){perror("semget");return -2;}return semid;}} int createSem(int nums) //创建 {return commSemMessage(nums,IPC_CREAT|IPC_EXCL|0666);}int getSem(int nums) //获取 {return commSemMessage(nums,IPC_CREAT);}int destroySem(int semid) //删除 {if(semctl(semid,0,IPC_RMID,NULL)<0) //IPC_RMID立即删除semid信号量集中数组下标为第0个信号量 {perror("destroy:semctl");return -1;}return 0;}int initSem(int semid,int nums,int initVal){union semun _un;_un.val=initVal;if(semctl(semid,nums,SETVAL,_un)<0) //对semid信号量集中第nums个信号量进行SETVAL操作将联合中_un成员val设为初始值initVal {perror("semctl");return -1;}return 0;}static int commPV(int semid,int nums,int initop){struct sembuf _buf;_buf.sem_num=nums; //信号量集中哪一个信号量 _buf.sem_op=initop; //P:-1, V:1_buf.sem_flg=0; //此处默认为0 if(semop(semid,&_buf,1)<0) {perror("semop");return -1;}return 0;}int P(int semid,int nums) {return commPV(semid,nums,-1);}int V(int semid,int nums){return commPV(semid,nums,1);}
comm.h
#ifndef COMM_H__#define COMM_H__#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <unistd.h>#include <errno.h>#define PATH "."#define PROJ_ID 0x6666union semun{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;};int createSem(int nums);int getSem(int nums);int initSem(int semid,int nums,int initVal);int destroySem(int semid);int P(int semid,int nums);int V(int semid,int nums);#endif
结果如下:
- 进程间通信 信号量
- 进程间通信--信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 【进程间通信】信号量
- 进程间通信----信号量
- 进程间通信:信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 进程间通信--信号量
- 进程间通信---->信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 进程间通信----信号量
- 进程间通信-信号量
- bzoj 1119置换群
- 选择排序
- 自己搭建5节点分布式集群
- php-人员权限管理(RBAC)
- Hadoop基础教程-第5章 YARN:资源调度平台(5.5 YARN的调度器)(草稿)
- 进程间通信-信号量
- 尤jx的科研经验
- 从源码看kubernetes与CNI Plugin的集成
- h5语义化标签
- jsp内置对象
- Android studio 常用的插件
- What is difference between HashMap and Hashtable in Java?
- Python正则表达式之\b
- oracle11g rac环境搭建中linux DNS Server搭建