Linux_进程间通信_4)信号量

一.本质

    信号量就是一个计数器,用来计算可以资源的个数。也是一个等待队列,保存的是PCB指针。它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。

二.作用

    信号量主要用于进程的同步和互斥。

    互斥:由于各个进程间要访问共享资源,而这些资源需要排他使用,因此各个进程之间要竞争使用这些资源,我们将这种关系称为进程互斥。系统中某些资源一次只允许一个进程使用,称这些资源为临界资源或互斥资源。在进程中涉及到互斥资源的程序段叫临界区。例子:电影院购买电影票

    同步:多个进程需要相互配合才能完成一项任务。例子:公交车和售票员的关系

三.基本操作

     PV操作

    信号量:互斥:PV在同一进程中    同步:PV在不同的进程中

    信号量的值:S>0:S表示可用资源的个数   S=0:表示无可用资源,无等待进程  S<0:|S|表示等待队列中进程的个数。

四.PV原语

     P-->申请资源

     

    V--->释放资源

    

四.API

     1.创建和访问一个信号量集

        1)头文件:#include <sys/types.h>
                           #include <sys/ipc.h>
                           #include <sys/sem.h>

        2)函数原型:int semget(key_t key, int nsems, int semflg);

        3)函数参数:key 信号集名字   nsems  信号集中信号量的个数  semflg 权限标志,和创建文件时一样

        4)返回值:成功返回信号集的标识码,失败返回-1

    2.控制信号集

        1)头文件:和创建头文件相同

        2)函数原型:int semctl(int semid, int semnum, int cmd, ...);

        3)函数参数:semid 有创建函数返回的信号集标识码  semnum 信号集中信号量的序号   cmd将要执行的操作

                                  最后一个参数是联合体,一般自己定义,传地址

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

        5)cmd参数的几种情况:SETVAL设置信号量集中的信号量的计数值

                                                      GETVAL获取信号量集中的信号量的计数值

                                                      IPC_STAT 把semid_ds结构中的数据设置为信号集的当前关联值

                                                    IPC_SET在进程有足够权限的前提下,把信号集的当前关联值设置为semid_ds数据结构中给出的值

                                                     IPC_RMID删除信号集

 3.PV操作

     1)头文件:和创建头文件相同

     2)函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);

     3)函数参数:semid 信号集标识码  sops 指向结构体的指针  nsops信号量的个数

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

     5)sembuf结构体

         

五.举个例子

  //comm.c  
  1 #include "comm.h"
  2 
  3 int Createsem(int flag){
  4     int key=ftok(PATHNAME,FILENAME);
  5     int sem=semget(key,NUM,flag);
  6     if(sem==-1){
  7         perror("semget");
  8         return -1;
  9     }
 10     return sem;
 11 }
 12 
 13 int initsem(int sem,int value){
 14     union semun num;
 15     num.val=value;
 16     int init =semctl(sem,0,SETVAL,num);
 17     if(init==-1){
 18         perror("semctl");
 19         return -1;
 20     }
 21     return 1;
 22 }
 23 
 24 void  destorysem(int sem){
 25     int des=semctl(sem,0,IPC_RMID);
 26     if(des==-1){
 27         perror("semctl");
 28     }
 29 }
 30 
 31 int handle(int sem,int _sem_num,int op){
 32     struct sembuf buf;
 33     buf.sem_num=_sem_num;
 34     buf.sem_op=op;
 35     buf.sem_flg=0;
 36 
 37     int sep=semop(sem,&buf,1);
 38     if(sep==-1){
 39         perror("semop");
 40         return -1;
 41     }
 42     return 1;
 43 }
 44 
 45 int P(int sem,int who){
 46     return handle(sem,who,-1);
 47 }
 48 
 49 int V(int sem,int who){
 50     return handle(sem,who,1);
 51 }
  //comm.h
  1 #include <sys/sem.h>                                        
  2 #include <sys/types.h>
  3 #include <sys/ipc.h>
  4 #include <unistd.h>
  5 union semun{
  6     int val;
  7     struct semid_ds *buf;
  8     unsigned short *array;
  9     struct seminfo *__buf;
 10 };
 11 
 12 #define PATHNAME "."
 13 #define FILENAME 0x008
 14 #define NUM 1
 15 
 16 int Createsem(int flag);
 17 int initsem(int sem,int value);
 18 void  destorysem(int sem);
 19 int handle(int sem,int _sem_num,int op);
 20 int P(int sem,int who);
 21 int V(int sem,int who);
 22 
  //fork.c
  1 #include "comm.h"
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <wait.h>
  5 #include <sys/types.h>
  6 int main(void){
  7     pid_t pid=fork();
  8     int sem=Createsem(IPC_CREAT|0644);
  9     initsem(sem,1);
 10     if(pid==0){
 11         int _sem=Createsem(0);
 12 
 13         while(1){
 14         P(_sem,0);
 15         printf("C");
 16         fflush(stdout);
 17         printf("C  ");
 18         fflush(stdout);
 19         usleep(20000);
 20         V(_sem,0);
 21         }
 22     }else if(pid>0){
 23         while(1){
 24         P(sem,0);
 25         printf("F");
 26         fflush(stdout);
 27         printf("F  ");
 28         fflush(stdout);
 29         usleep(20000);
 30         V(sem,0);
 31         }
 32         wait(NULL);
 33     }
 34     destorysem(sem);
 35     return 0;
 36 }              

运行结果

猜你喜欢

转载自blog.csdn.net/warrior_harlan/article/details/81154986