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