信号量

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

进程互斥:系统中某些资源在一段时间只能允许一个进程使用,这种资源较临界资源,或者互斥资源,而通常由于各个进程要求共享资源,但是临界资源需要互斥使用,因此各个进程间竞争使用这些临界资源,进程间的这种关系叫做进程间的互斥。

进程同步:多个进程需要相互配合共同完成一项任务。

信号量:互斥是P,V在同一个进程;同步是P,V在不同进程中。信号量值S>0,S表示资源可用的个数,S=0,S表示无可用资源,无等待资源进程,S<0,|S|表示等待资源的个数。

P使得资源数减1,V使得资源数加1

关于信号量,我们主要研究以下内容:

(1)创建信号量

System V中的信号量又叫信号量集,因为里面可以有多个信号量

 6 int main()
  7 {
  8     //创建名为1234的信号量集,里面有一个信号量,并且给权限不受umask值影响
  9     int id=semget(1234,1,IPC_CREAT|0644);
 10     printf("creat is ok\n");
 11     return 0;
 12 }

(2)给信号量设定初值

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/ipc.h>
  4 #include <sys/sem.h>
  5 
  6 //用来给信号量设定初值的联合体                                                      
  7 union semun
  8 {   
  9     int value;
 10 };
 11 int main()
 12 {   
 13     //创建名为1234的信号量集,里面有一个信号量,并且给权限不受umask值影响
 14     int id=semget(1234,1,IPC_CREAT|0644);
 15     printf("creat is ok\n");
 16     
 17     printf("请给信号量设定初值:");
 18     int num;
 19     scanf("%d",&num);
 20     union semun su;//将手动输入的初值,放到联合体里中对应放信号量初值的地方
 21     su.value=num;
 22     //给id这个信号量的第(0)个信号量设置初始值为su联合体中的值
 23     semctl(id,0,SETVAL,su);
 24     return 0;
 25 }

(3)获得信号量的当前值

//获取id这个信号量集第(0)个信号量的初始值                                     
   3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <sys/ipc.h>
  6 #include <sys/sem.h>
  7 
  8 
  9 int main()
 10 {
 11     int id=semget(1234,0,0);
 12      int ret=semctl(id,0,GETVAL);
 13      printf("%d\n",ret);
 14 
 15     return 0;
 16 }

(4)P,V操作

P操作:
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <sys/ipc.h>
  5 #include <sys/sem.h>
  8 void p(int id)
  9 {
 10     struct sembuf sb[1];//p/v操作要操作这个结构体,1个元素表明有一个信号量
 11     sb[0].sem_num=0;//要操作第几个信号量(本案例只有一个,就按下标为0)
 12     sb[0].sem_op=-1;//p操作是负数(-1)
 13     sb[0].sem_flg=0;//默认给0
 14     //调用p操作函数
 15     //给id这个信号量,操作都在sb这个结构体中,结构体有一个元素(即一个信号量)
 16     semop(id,sb,1);
 17 }
 18 int main()
 19 {
 20     //打开一个信号量,由于1234这个信号量上一个文件已经创建
 21     int id=semget(1234,0,0);
 22     p(id);
 23     return 0;
 24 }
V操作:
只需要把P操作中的sb[0].sem_op=-1改为 sb[0].sem_op=1即可

互斥操作的小案例:

父子进程同时往屏幕上输出内容,即使每个进程输出时沉睡一会,但是由于打印函数有P/V操作,因此总会使得每个进程打印的东西不会中断。

实现:

 1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/ipc.h>
  4 #include <sys/sem.h>
  5 
  6 //用来设置信号量初值的联合体
  7 union semun
  8 {
  9     int value;
 10 };
 11 int id;//信号量设为全局变量,因为两个函数都要使用
 12 
 13 //测试打印函数
 14 void print(char c)
 15 {
 16     int i;
 17     for(i=0;i<5;i++)
 18     {
 19         struct sembuf sb[1];
 20         sb[0].sem_num=0;
 21         sb[0].sem_op=-1;
 22         sb[0].sem_flg=0;
 23 
 24         //p操作
 25         semop(id,sb,1);
 26         printf("%c",c);
 27         fflush(stdout);
 28         sleep(rand()%3);
 29         printf("%c",c);
 30         fflush(stdout);
 31 
 32         //v操作
 33         sb[0].sem_op=1;
 34         semop(id,sb,1);
 35         sleep(rand()%3);
 36     }
 37 }
 38 int main()
 39 {
 40     //创建信号量
 41     id=semget(12345,1,IPC_CREAT|0644);
 42     if(id==-1)
 43     {
 44         perror("semget\n");
 45         exit(1);
 46     }
 47     //给信号量设置初值位1
 48     union semun su={1};
 49     semctl(id,0,SETVAL,su);
 50 
 51     //创建子进程、
 52     pid_t pid=fork();
 53     if(pid==0)//子进程
 54     {
 55         print('o');
 56     }
 57     else if(pid>0)
 58     {
 59         print('x');
 60     }
 61     return 0;
 62 }







猜你喜欢

转载自blog.csdn.net/lyl194458/article/details/80089973