C语言实现PV操作典型程序
PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
概念
临界区**指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。
临界区调度原则:
1、如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。
2、任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待。
3、进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。
4、如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。
信号量(semaphore): 可用于进程间同步也可用于同一个进程间的线程同步。
信号量有一个使用计数器,这个使用计数器,是信号量的最大资源计数和当前资源计数的差值。
计数器的值大于0时,表示当前可用资源个数。
计数器的值小于0时,表等待使用资源的进程个数。
计数器的值为0则既没有可用资源也没有等待资源的进程
假设S的为信号量的计数器的值:
P操作:执行一次P操作意味着请求分配一个单位的资源,因此S的值减1,当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能继续运行。
V操作:执行一次V操作意味着释放一个资源,因此S的值加1,当S<0,表示有某些进程正在等待资源,因此要唤醒一个等待状态的进程,使之继续运行。
实例
PV操作解决问题可以套用一个固定的代码demo~就是一个while里套三个部分:开头一个P结尾一个V中间是临界区,
使用PV操作来解决问题:爸爸放苹果,女儿拿苹果,妈妈放橘子,儿子拿橘子。
由题可以看出需要4个进程,爸爸和妈妈的进程需要执行放的操作,我们分别套用模型即可
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include<semaphore.h>
#define P sem_wait
#define V sem_post
#define full_apple &fullA
#define full_orange &fullB
#define empty &empty_aha
sem_t fullA;
sem_t fullB;
sem_t empty_aha;
int num=0;
void* Dad(void *p)
{
while(num<50)
{
P(empty);
num++;
printf("老爸放了个苹果%d
",num);
V(full_apple);
}
}
void* Dangter(void *p)
{
while(num<50)
{
P(full_apple);
num++;
printf("女儿吃了个苹果%d
",num);
V(empty);
}
}
void* Mum(void *p)
{
while(num<50)
{
P(empty);
num++;
printf("老妈放了个橘子%d
",num);
V(full_orange);
}
}
void* Son(void *p)
{
while(num<50)
{
P(full_orange);
num++;
printf("儿子吃了个橘子%d
",num);
V(empty);
}
}
int main()
{
sem_init(full_apple, 0, 0);
sem_init(full_orange, 0, 0);
sem_init(empty, 0, 1);
pthread_t tid0;
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
pthread_create(&tid0, NULL, Dad, NULL);
pthread_create(&tid1, NULL, Mum, NULL);
pthread_create(&tid2, NULL, Son, NULL);
pthread_create(&tid3, NULL, Dangter, NULL);
getchar();
pthread_exit(0);
return 0;
}