临界资源:具有排他性的资源
临界区:访问临界资源的代码段
信号量的本质就是计数器
互斥访问
操作系统的P操作就是上锁,V操作就是解锁
上锁() 解锁()
{ {
计数器-- 计数器++
if(计数器<0) if(计数器<=)
{ {
进入阻塞状态 唤醒阻塞队列
放入阻塞队列 }
} }
}
举个例子:
我们常见的购票就可以理解为互斥,当用户1和用户2都有购票需求时,假设用户1先访问购票系统,如果没有互斥锁,用户1运行if(票数>0)发现还有一张票果断下单购买,这时用户1进程运行的时间片到了,切换到用户2,用户2运行if(票数>0)由于票数还没来得及--,此时还显示着票数为1,这样就会导致用户1与2都买了同一张票,这显然是不行的。这就要求我们上锁,在用户1购买的时候加锁,哪怕时间片到了切换到用户2,由于锁的限制用户2无法访问,也就无法购买了。那么我们如何控制互斥锁呢?这里就要引出信号量。这里让信号量为1,每次P申请锁,信号量--,每次V释放锁,信号量++。图示如下
进程同步:
标准概念:进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。
举个例子:
我们常见的司机与售票员之间的故事:当乘客们已经顺利登车,司机要开门必须要等售票员关好门才可以,同理售票员要开门必须要等司机到站停车才可以。这两者之间的关系就是同步。示例如图:
创建或打开信号量:
int semget(key_t key,int nsems,int flags)
nsems:信号量集中信号量的个数
flags:打开 0
创建IPC_CREAT|0644
具体代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 int main()
6 {
7 int id=semget(123,1,IPC_CREAT|0644);
8 if(id==-1)
9 {
10 perror("id");
11 exit(1);
12 }
13 printf("semget success!\n");
14 }
验证是否创建成功:
这里的nsems表示信号量集中有多少个信号量
设置信号量初值:
semctl(int semid,int semnum,int cmd,su);
semnum:信号量集中的第几个信号量
cmd:命令,这里用SETVAL
union semun{
int val;//设定信号量的值
}
具体代码:
1 #include<stdio.h>
2 #include<sys/ipc.h>
3 #include<sys/sem.h>
4 #include<stdlib.h>
5 union semun{
6 int val;
7 };
8 int main()
9 {
10 int id=semget(123,0,0);
11 if(id==-1)
12 {
13 perror("id");
14 exit(1);
15 }
16 union semun su;
17 su.val=5;
18 semctl(id,0,SETVAL,su);
19 }
查看信号量的值:
int semctl(int semid,int semnum,int cmd,0)
semnum:信号量集中的第几个信号量
cmd:命令,这里为GETVAL
0:无需再重复定义联合体
返回值为当前信号量的值
具体代码:
1 #include<stdio.h>
2 #include<sys/ipc.h>
3 #include<sys/sem.h>
4 #include<stdlib.h>
5 int main()
6 {
7 int id=semget(123,0,0);
8 if(id==-1)
9 {
10 perror("id");
11 exit(1);
12 }
13 int val=semctl(id,0,GETVAL,0);
14 printf("val=%d",val);
15
16 }
PV操作:
semop (int id,struct sembuf sb[],int len)
len:数组的长度
struct sembuf{
short sem_num, //信号量的下标
short sem_op, // 1表示V操作,-1表示P操作
short sem_flg //一般填0,表示如果信号量为0就阻塞
};
P操作具体代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 void p(int id)
6 {
7 struct sembuf sb[1];
8 sb[0].sem_num=0;
9 sb[0].sem_op=-1;
10 sb[0].sem_flg=0;
11 semop(id,sb,1);
12 }
13 int main()
14 {
15 int id=semget(123,0,0);
16 if(id==-1)
17 {
18 perror("semget");
19 exit(1);
20 }
21 p(id);
22 }
V操作具体代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/ipc.h>
4 #include<sys/sem.h>
5 v(int id)
6 {
7 struct sembuf sb[1];
8 sb[0].sem_num=0;
9 sb[0].sem_op=1;
10 sb[0].sem_flg=0;
11 semop(id, sb,1);
12 }
13 int main()
14 {
15 int id=semget(123,0,0);
16 if(id==-1)
17 {
18 perror("semget");
19 }
20 v(id);
21
22 }