信号量主要是用于进程同步和互斥的。
进程互斥:系统中某些资源在一段时间只能允许一个进程使用,这种资源较临界资源,或者互斥资源,而通常由于各个进程要求共享资源,但是临界资源需要互斥使用,因此各个进程间竞争使用这些临界资源,进程间的这种关系叫做进程间的互斥。
进程同步:多个进程需要相互配合共同完成一项任务。
信号量:互斥是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 }