进程间通信——信号量

xiaoxiao2021-02-28  134

信号量 信号量的作用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。 信号量的值为正的时候,说明它空闲。测试的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。 为什么要使用信号量? 因为共享内存是可以由多个进程同时访问,假如有多个进程同时访问同一块地址的话,内存就会出错,或者是 运算错误,所以当某个进程访问共享内存的时候,我们利用信号量去保护这片共享内存以防内存出错。 信号量的分类 在学习信号量之前,我们必须先知道—— Linux 提供两种信号量: (1) 内核信号量,由内核控制路径使用 (2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量SYSTEM V信号量 POSIX信号量又分为有名信号量无名信号量                有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步。                无名 信号量,其值保存在内存中。 信号量的使用步骤 1.创建信号量---》 semget 2.初始化信号量---》 semctl 3.进行信号量的操作---》 semop 1.创建信号量 头文件:     #include <sys/types.h>     #include <sys/ipc.h>     #include <sys/sem.h> 函数原型:     int semget(key_t key, int nsems, int semflg); 参数一:秘钥ftok() 参数二:需要创建信号量的个数 PS:(信号量是有个数的他从0下标开始) 参数三:权限 IPC_CREAT  -》创建 IPC_EXCL   -》检查 |0666       -》操作权限 返回值:信号量对象ID 失败返回:-1  2.初始化信号量 int semctl(int semid, int semnum, int cmd, ...); 参数一:要初始化的信号量对象ID 参数二:要初始化那个信号量 参数三:命令  GETVAL -》获取当前信号量的值(一般设备完毕后需要获取一下值 ,该值会放到返回值中)      SETVAL  -》设置信号量的值   (该值应该填写到第4个参数中)      IPC_RMID -》删除信号量对象 参数四:通过命令来确定他的值    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) */ }; 3.进行信号量的P\V操作  p -> 申请资源            V -> 释放资源 头文件:             #include <sys/types.h>            #include <sys/ipc.h>          #include <sys/sem.h> 函数原型:     int semop(int semid, struct sembuf *sops, unsigned nsops); 参数一:对象ID 参数二:操作结构体  struct sembuf  {    unsigned short sem_num;  /* semaphore number */要操作哪一个信号量            short          sem_op;   /* semaphore operation */PV操作  P操作 填写 -1           V操作 填写  1            short          sem_flg;  /* operation flags */                     IPC_NOWAIT  不阻塞 SEM_UNDO  -》自动释放资源 0       -》默认操作  } 参数三:整形  -》 指定参照二的结构体数量  一般填写为1  ----------------------------------------------------------------------------------------- 练习:使用信号量的pv操作 【sema.c】 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #include <stdlib.h> int main() { //创建信号量对象 int semid=semget(ftok("/home/gec",400),2,IPC_CREAT|0666); if(semid == -1) { perror("semid fail:"); exit(0); } else { printf("crete ok\n"); } //对信号量1进行初始化 int ret=semctl(semid,0,SETVAL,1); if(ret == -1 ) { perror(" init sem:"); exit(0); } else { printf("init 1 ok %d\n",semctl(semid,0,GETVAL,NULL)); } //对信号量2进行初始化 ret=semctl(semid,1,SETVAL,1); if(ret == -1 ) { perror(" init sem:"); exit(0); } else { printf("init 2 ok %d\n",semctl(semid,0,GETVAL,NULL)); } //进行P-1 V+1操作 struct sembuf p; p.sem_num = 0; //要操作哪一个信号量 p.sem_op = -1; // -1为P操作 1为V操作 p.sem_flg = 0; //默认属性 struct sembuf v; v.sem_num = 0; v.sem_op = 1; v.sem_flg = 0; //进行PV操作2 struct sembuf p1; p1.sem_num = 1; //要操作哪一个信号量 p1.sem_op = -1; // -1为P操作 1为V操作 p1.sem_flg = 0; //默认属性 struct sembuf v1; v1.sem_num = 1; v1.sem_op = 1; v1.sem_flg = 0; int i=0; while(1) { //进行P操作 semop(semid,&p,1); printf("i=%d\n",i++); sleep(1); //进行V操作 semop(semid,&v1,1); } } 【semb.c】 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #include <stdlib.h> int main() { //创建信号量对象 int semid=semget(ftok("/home/gec",400),2,IPC_CREAT|0666); if(semid == -1) { perror("semid fail:"); exit(0); } else { printf("crete ok\n"); } //进行P-1 V+1操作 struct sembuf p; p.sem_num = 0; //要操作哪一个信号量 p.sem_op = -1; // -1为P操作 1为V操作 p.sem_flg = 0; //默认属性 struct sembuf v; v.sem_num = 0; v.sem_op = 1; v.sem_flg = 0; //进行PV操作2 struct sembuf p1; p1.sem_num = 1; //要操作哪一个信号量 p1.sem_op = -1; // -1为P操作 1为V操作 p1.sem_flg = 0; //默认属性 struct sembuf v1; v1.sem_num = 1; v1.sem_op = 1; v1.sem_flg = 0; int i=0; while(1) { //进行P操作 semop(semid,&p1,1); printf("i=%d\n",i++); sleep(1); //进行V操作 semop(semid,&v,1); } } 运行程序sema.c,初始化信号量1,2,运行semb.c后,两个进程的变量i每隔1s加1.
转载请注明原文地址: https://www.6miu.com/read-39102.html

最新回复(0)