操作系统——2.2-3经典进程的同步问题

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);
}

读者-写者问题,读者优先需要注意:只要有读进程还在读,写进程就要一直阻塞等待,可能“饿死”

上一篇:力扣1226. 哲学家进餐(信号量)


下一篇:JUC并发编程 -- ReentrantLock可重入锁(可重入 & 可打断 & 锁超时 & 锁超时-解决哲学家就餐)