目录
- 信号量概述:
-
- 一:信号量的本质
- 二:信号量的机制
- 相关的API
-
-
- ***①int semget(key_t key,int num_sems,int sem_flags);***
- ***②int semop(int semid,struct sembuf semoparray[ ],size_t semops);***
- ***③int semctl (int semid,int sem_num,int cmd,…)***
-
- 例子
信号量概述:
一:信号量的本质
???信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。==当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。
二:信号量的机制
??信号量用于实现进程间的互斥与同步,而不是用于存储进程间的通信数据。举例子来理解这句话:
把一个临界资源(也可以认为是共享内存)比作一个上了锁的房间,某人比作一个进程,而开锁的钥匙就是信号量。某人有钥匙的话,就能开锁进入房间里,做它需要做的事情,如果这时候有第二个人想进入房间里的话,是进不去的,因为它没有钥匙(信号量(钥匙)<0)。直到进去的那个人出了房间把钥匙放在某个地方(使信号量(钥匙)>=0),然后第二人拿到了钥匙,才能渠道房间里去。这钥匙起到的作用就是信号量。若有100把钥匙,可以使101个人同时进入房间。
PV操作的定义:
P:
①将信号量S的值减1,即进行S = S-1;
??②如果S < 0,则该进程进入阻塞队列;
??③如果S >= 0, 则该进程继续执行;
??④执行一次P操作其实就是意味请求分配一个资源。
V:
??①将信号量S的值加1,即 S = S + 1;
??②如果S > 0,则该进程继续执行;
??③如果S < 0, 则释放阻塞队列中的第一个等待信号量的进程;
??④执行一次V操作其实就是意味释放一个资源。
相关的API
头文件:
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>
①int semget(key_t key,int num_sems,int sem_flags);
??功能:(semphore get)创建或获取信号量,返回信号量D。
??参数:
???? key:信号量索引值,可使用ftok获取
????num_sems:指定需要的信号量数目,它的值几乎总是1
????sem_flags:一般用IPC_CREAT 加上权限创建信号量集
??返回值:成功返回信号集的ID;失败返回 ==-1 ==;
②int semop(int semid,struct sembuf semoparray[ ],size_t semops);
??功能:(semphore operation)它的作用是改变信号量的值(PV操作)
??参数:
???? semid:目标信号量的ID号
????semoparray[]:结构体数组,它有三个成员:
???? ????(1)sem_num:需要操作第几个信号量;
???? ????(2)sem_op:信号量的值,-1为p操作(拿钥匙);1为v操作(放钥匙)。
???? ????(3)sem_flg:一般赋值SEM_UNDO相当于wait;
???? semops :semoparray[] 数组的个数。
??返回值: 成功返回0;失败返回 -1;
③int semctl (int semid,int sem_num,int cmd,…)
如果有第四个参数,它通常是一个union semun结构,定义如下:
union semun {
int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */};
控制信号量函数。用来控制信号,比如初始化,移除信号量等。
参数说明:
????1. semid 被操作目标信号量的ID号;
????2. sem_num 信号量的个数,即需要操作第几个信号量;从0开始计数。
????3. cmd 操作指令,它有几个宏,常用一般用SETVAL (初始化信号量的值相当于钥匙的数量)IPC_RMID:用于删除一个信号量标识符。
????4. 其他 这个参数,是配合SETVAL指令来使用,它是个联合体而且需要定义。
例子
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<stdio.h>
#include<stdlib.h>
// int semget(key_t key, int nsems, int semflg);
// int semctl(int semid, int semnum, int cmd, ...);union semun {
int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */};
void Pop(int semid){
int ret;struct sembuf sembuf[1];sembuf[0].sem_num=0;sembuf[0].sem_op=-1;sembuf[0].sem_flg=SEM_UNDO;ret=semop(semid,sembuf,1);if(ret == -1){
printf("get key faied\n");}else{
printf("get key sucess\n");}
}
void Vop(int semid){
int ret;struct sembuf sembuf[1];sembuf[0].sem_num=0;sembuf[0].sem_op=1;sembuf[0].sem_flg=SEM_UNDO;ret=semop(semid,sembuf,1);if(ret == -1){
printf("return key faied\n");}else{
printf("return key sucess\n");}
}
int main(){
key_t key;int semid;int pid;union semun semclt;semclt.val=0; //信号量的数量key=ftok(".",6);semid=semget(key,1,IPC_CREAT|0666);semctl(semid,0,SETVAL);//删除信号量IDpid=fork();if(pid>0){
Pop(semid); // 减去一个信号量,由于<0程序阻塞printf("this is parent pid\n");semctl(semid,0,IPC_RMID,semctl);} else if(pid==0){
printf("this is child pid\n");Vop(semid);//加上一个信号量。使信号量=0父进程运行}else{
printf("fork faile\n");}return 0;
}