信号量概念理解
- 信号量本质上 是一个计数器,用来统计临界资源申请资源的个数。其中的二元信号量的 值是0或者是1,即是要么是有,要么是无。信号量本身也是临界资源,所以一定要保证其原子性。
- 信号量的工作原理:两个进程共享一个信号量sv,一个进程访问的sv的时候,进行的是P操作即是减1操作,开始的时候信号量是1,它得到信号量进入临界资源。当他出来的时候进行v操作,使信号量加1。其他的进程访问的时候看见信号量是0,就不在访问了。
- 现实形象比喻:比如我们的信号量是一个教室的,教室里面有很多座位,这就是临界资源。咱们设计是50,一开始同学想进教室的时候得去申请,比如现在门口站了一个人,它就是控制信号量的,第一个人进去的时候,使用P操作,将50减1,出来的时候加1,如果信号量是>0的 就可以进去,否则就不可以进去
- 信号量 不以传送数据为目的,它是以协调使用临界资源进行 进程间通信为目的的,当我们申请信号量的时候,就可以得到信号量保护的临界资源。
信号量相关函数的使用
得到信号量(生成信号量)
int semget(key_t key,int nsem,int semflg)
参数解析
- key:这是一个key值,可以理解为一个端口,这个用函数ftok生成,一会介绍
- nsem:信号量的个数
- semflg:创建信号量的方式,它由两个固定标识位参数可以选择。如果是IPC_CREAT,表示如果有一个信号量则返回,如果没有则创建。IPC_EXCL,如果单独使用它没有任何的意义,但是如果和IPC_CREAT一起使用,就是IPC_CREAT|IPC_EXCL表示如果有信号量则出错返回,如果没有则创建,这样就可以保证我们每次使用的时候创建的是一个全新的信号量
返回值
如果失败返回-1,如果成功返回信号量标识符(信号量ID)
删除信号量
int semctl(int semid,int semnum,int cmd,...)
参数:
- semid:这个是删除的信号量的标识符(ID)
- semnum:这个是删除的信号量的个数,这里暂时设置0
- cmd:执行命令的方式,这里我们主要是为了删除一个信号量,可以直接使用IPC_RMID
初始化信号量
int semctl(int semid,int semnum,int cmd,...)
- semid:这个是初始化信号量的标识符(ID)
- semnum:这个是初始化信号量中的第几个信号量,数组下标的形式
- cmd:执行命令的方式,这里我们是初始化信号量,传入的是特定的参数SETVAL,传入这个信号量的时候,需要传入第四个参数,这个参数应该是一个联合体,联合体的结构如下
union semnu{
int val; // 使用的值
struct semid_ds *buf; // IPC_STAT、IPC_SET 使用缓存区
unsigned short *array; // GETALL,、SETALL 使用的数组
struct seminfo *__buf; // IPC_INFO(Linux特有) 使用缓存区
};
我们在使用semctl进行 信号量初始化的时候,首先得先用上面的联合体定义一个对象,然后这个联合体是需要我们自己定义的,然后把实例化的这个对象的val设置为1(这里我们使用的是二元信号量)
函数使用示例:
union semnu _semnu;
semctl(semid,semnum,SETVAL,_semnu);
返回值:失败返回-1
信号量Pv操作
int semop(int semid,struct sembuf* sops,unsigned nsops)
参数
- semid:信号量标识符
- sops:这个也是需要我们提前实例化一个对象,这里我们可以传递的是一个结构体数组,也可以是一个结构体的地址
- nspos:是结构体的个数,因为上一个参数是一个数组
这里第二个参数也是一个结构体,这个结构体是系统自定义的结构体,不需要我们定义,我们可以直接调用它,这里结构体的内容 如下
struct sembuf{
unsigned short sem_num;
short sem_op;
short sem_flag;
};
num:标记信号量集中的第几个
sem_op:标记是那种操作,比如二元信号量p设置为-1,如果是v操作设置为1
sem_flag:我们此时默认设置为0
讨论信号量的几种情况
- 当我们的某一个进程已经进行 p操作,拿到信号量维护的共享资源之后,这个时候可以有一种可能该进程被其他进程替换掉了,但是这个时候信号量依然被该进程拿着,等它下一次切换进来的时候还可以继续原来的操作
- 另外的一种情况是,某一进程拿到信号量之后,因为某些原因被杀死,这个时候信号量还在改进程里面,其他的进程就无法获得该信号量,这个情况就是问题所在。这个时候我们可以设置信号量的的结构体,就是上面的结构体sem_flag,可以把它设置为SEM_UNDO,这个时候进程退出的时候,它所拿到的信号量就会释放掉,比如二元信号量原来是0,如果使用这个选项后,当进程退出后就会变成是1。
补充两个linux的指令:
- ipcs -s :查看当前信号量
- ipcrm -s 信号量标识符:删除某一个信号量
- ipcs -q:查看当前消息队列数
- ipcrm -q 消息队列标识符:删除某一个消息队列
信号量原理与应用
1027

被折叠的 条评论
为什么被折叠?



