1.生产者-消费者问题
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。
- 生产者、消费者共享一个初始为空、大小为n的缓冲区,各进程互斥访问
- 缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
- 缓冲区不空时,消费者才能从中取出产品,否则必须等待
semaphore mutex = 1;//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;//同步信号量,表示空闲缓冲区的数量
semaphore full = 0; //同步信号量,表示产品的数量,即非缓冲区的数量
producer(){
while(1){
生产一个产品;
P(empty);//消耗一个空闲缓冲区
P(mutex);
把产品放入缓冲区;
V(mutex);
V(full);//增加一个产品
}
}
consumer(){
while(1){
P(full);//消耗一个产品
P(mutex);
从缓冲区取出一个产品;
V(mutex);
V(empty);//增加一个空闲缓冲区
使用产品;
}
}
2.哲学家进餐问题
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时, 才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
(主要是解决死锁现象的发生)
有三种方案
//1.对哲学家施加限制(如最多只有4个哲学家可以同时进餐,那么至少可以保证一个哲学家可以同时拿到左右两支筷子
semaphore chopstick[5] = {1,1,1,1,1};
int num = 4;
Pi(){
P(chopstick[i]);
P(chopstick[(i+1)%5]);
吃饭;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
思考;
}
//2.要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子
// 而偶数号哲学家先拿右边的筷子,然后再拿左边的筷子
semaphore chopstick[5] = {1,1,1,1,1};
Pi(){
if(i%2==1){
P(chopstick[i]);
P(chopstick[(i+1)%5]);
}
else{
P(chopstick[(i+1)%5]);
P(chopstick[i]);
}
吃饭;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
思考;
}
//3.仅当一个哲学家可以同时拿起两支筷子时,才允许他拿起筷子
//(1)使用AND信号量集
semaphore chopstick[5] = {1,1,1,1,1};
Pi(){
P(chopstick[i],chopstick[(i+1)%5]);
吃饭;
V(chopstick[i],chopstick[(i+1)%5]);
思考;
}
//(2)使用互斥信号量
semaphore chopstick[5] = {1,1,1,1,1};
semaphore mutex = 1;
Pi(){
P(mutex);
P(chopstick[i]);
P(chopstick[(i+1)%5]);
V(mutex);
吃饭;
P(chopstick[i]);
P(chopstick[(i+1)%5]);
}
3.读者-写者问题
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时没有影响,但是某个写进程和其他进程(读或写)同时访问则可能导致数据不一致的错误。
- 允许多个读者可以同时对文件执行读操作
- 只允许一个写者往文件中写信息
- 任一写者在完成写操作之前不允许其他读者或写者工作
- 写者执行写操作前,应让已有的读者和写者全部退出
semaphore rwmutex = 1;//保证写操作和读操作的互斥
semaphore rmutex = 1;//防止读操作之间发生阻塞
int rcount = 0;//记录读进程的数量
writer(){
P(rwmutex);
写操作;
V(rwmutex);
}
reader(){
P(rmutex);
if(count == 0)
P(rwmutex);
count++;
V(rmutex);
读操作;
P(rmutex);
count--;
if(count == 0)
V(rwmutex);
V(rmutex);
}
读者-写者问题,读者优先需要注意:只要有读进程还在读,写进程就要一直阻塞等待,可能“饿死”