写在前面:
转载请注明本文链接:https://www.cnblogs.com/jxingh/p/15624566.html
PV 操作
1、生产者-消费者问题

semaphore empty = n; // 表示空闲缓冲区的数量
semaphore full = 0; // 表示满缓冲区的数量
semaphore mutex = 1;
producer(){ // 生产者
while(1){
生产一个产品;
P(empty);
P(mutex);
向缓冲区放入该产品;
V(mutex);
V(full);
}
}
consumer(){
while(1){
P(full);
P(mutex);
从缓冲区取出一件产品;
V(mutex);
V(empty);
消费一个产品;
}
}
2、读者-写者问题
①允许多个读者可以同时对文件执行读操作;
②只允许一个写者往文件中写信息;
③任一写者在完成写操作之前不允许其他读者或写者工作;
④写者执行写操作前,应让已有的读者和写者全部退出。
// 读者优先
// 当存在读进程时,写操作将被延迟,并且只要有一个读进程活跃,随后而来的读进程都将被允许访问文件
// 会导致写进程可能长时间等待,且存在写进程“饿死”的情况
int readcount = 0; // 表示正在进行读的读者数目
semaphore rmutex = 1; // 实现多个读者对readcount的互斥访问
semaphore mutex = 1; // 实现对文件的互斥访问
reader(){
while(1){
P(rmutex);
if(readcount==0) P(mutex); // 第一个读者
readcount++;
V(rmutex);
读操作;
P(rmutex);
readcount--;
if(readcount==0) V(mutex); // 最后一个读者
V(rmutex);
}
}
writer(){
while(1){
P(mutex);
写操作;
V(mutex);
}
}
// 读写公平
// 无论是读者还是写者,都按他们到达的时间先后决定优先次序
int readcount = 0;
semaphore rmutex = 1;
semaphore mutex = 1;
semaphore S = 1; // 实现先到的先进行读或写操作
reader(){
while(1){
P(S);
P(rmutex);
if(readcount==0) P(mutex);
readcount++;
V(rmutex);
V(S);
读操作;
P(rmutex);
readcount--;
if(readcount==0) V(mutex);
V(rmutex);
}
}
writer(){
while(1){
P(S);
P(mutex);
V(S);
写操作;
V(mutex);
}
}
// 写者优先
// 先于写者到达的读者比写者优先,但写者到达后,其后续读者必须等待写操作完成
// 写完成之前,有新的写者到来,其优先权高于已在等待的读者
int readcount = 0, writecount = 0;
semaphore rmutex = 1, wmutex = 0; // 分别实现读者、写者对readcount、writecount的互斥访问
semaphore mutex = 1;
semaphore S = 1;
reader(){
while(1){
P(S);
P(rmutex);
if(readcount==0) P(mutex);
readcount++;
V(rmutex);
V(S);
读操作;
P(rmutex);
readcount--;
if(readcount==0) V(mutex);
V(rmutex);
}
}
writer(){
while(1){
P(wmutex);
if(writecount==0) P(S); // 第一个写者
writecount++;
V(wmutex);
P(mutex);
写操作;
V(mutex);
P(wmutex);
writecount--;
if(writecount==0) V(S); // 最后一个写者
V(wmutex);
}
}
// 写者优先
// 写者优先权更高。某个写者到达后,即使前面没有写者,那先于他到达但还没来得及读的读者必须等待他完成写操作
int readcount = 0, writecount = 0;
semaphore rmutex = 1, wmutex = 0; // 分别实现读者、写者对readcount、writecount的互斥共享
semaphore mutex = 1;
semaphore S = 1;
semaphore RS = 1;
reader(){
while(1){
P(RS); // 避免读者在S上排成长队
P(S);
P(rmutex);
if(readcount==0) P(mutex);
readcount++;
V(rmutex);
V(S);
V(RS);
读操作;
P(rmutex);
readcount--;
if(readcount==0) V(mutex);
V(rmutex);
}
}
writer(){
while(1){
P(wmutex);
if(writecount==0) P(S); // 第一个写者
writecount++;
V(wmutex);
P(mutex);
P(mutex);
写操作;
V(mutex);
P(wmutex);
writecount--;
if(writecount==0) P(S); // 最后一个写者
V(wmutex);
}
}
3、哲学家问题
(1)至多只允许4个哲学家同时进餐。
(2)仅当哲学家左右两边的筷子都可用时,才允许他进餐。
(3)规定奇数号哲学家先拿左边的筷子,再拿右边的筷子;而偶数号哲学家则先拿右边的筷子,再拿左边的筷子。
semaphore chopstick[5] = {1, 1, 1, 1, 1};
(1)
semaphore count = 4; // 设置一个count,最多有四个哲学家可以进餐
philosopher(int i){
while(true){
P(count); // 请求进餐,当count为0时,不能允许哲学家再进餐
P(chopstick[i]); // 请求左手边的筷子
P(chopstick[(i+1)%5]); // 请求右手边的筷子
i号哲学家进餐;
V(chopstick[i]); // 释放左手边的筷子
V(chopstick[(i+1)%5]); // 释放右手边的筷子
V(count); // 结束进餐
}
}
(2)
semaphore mutex = 1; // 对取左侧和右侧筷子的操作进行保护
philosopher(int i){
while(true){
P(mutex); // 保护信号量
P(chopstick[(i+1)%5]);
P(chopstick[i]);
V(mutex); // 释放保护信号量
i号哲学家进餐;
V(chopstick[(i+1)%5]);
V(chopstick[i]);
}
}
(3)
philosopher(int i){
while(true){
if(i%2 == 0){ //偶数哲学家,先右后左
P(chopstick[(i+1)%5]) ;
P(chopstick[i]) ;
i号哲学家进餐;
V(chopstick[(i+1)%5]) ;
V(chopstick[i]) ;
}
else{ //奇数哲学家,先左后右
P(chopstick[i]) ;
P(chopstick[(i+1)%5]) ;
i号哲学家进餐;
V(chopstick[i]) ;
V(chopstick[(i+1)%5]) ;
}
}
}
4、变形
(1)生产线问题
有三个进程PA、PB和PC合作解决⽂件打印问题。PA将⽂件记录从磁盘读⼊内存的缓冲区1,每执⾏⼀次读⼀个记录。PB将缓冲区1的内容复制到缓冲区2,每执⾏⼀次复制⼀个记录。PC将缓冲区2的内容打印出来,每执⾏⼀次打印⼀个记录。缓冲区的⼤⼩与记录⼤⼩一样。
semaphore empty1=1, full1=0, empty2=1, full2=0;
PA(){
while(1){
从磁盘读一个记录;
P(empty1);
将记录存放在缓冲区1中;
V(full1);
}
}
PB(){
P(full1);
从缓冲区1中取出一个记录;
V(empty1);
P(empty2);
将记录复制到缓冲区1中;
V(full2);
}
PC(){
P(empty1);
从缓冲区1中取出一个记录;
V(full1);
打印该记录;
}
(2)缓冲区划分
进程A1、A2、......、An1通过m个缓冲区向进程B1、B2、......、Bn2不断地发送消息。发送和接收工作遵循如下规则:
(1)每个发送进程一次发送一个消息,写入一个缓冲区,缓冲区大小和消息长度相同;
(2)对每一个消息,B1、B2、.......、Bn2都需要各接收一次,读入自己的数据区内;
(3)m个缓冲区都满时,发送进程等待;没有可读的消息时,接收进程等待。
https://blog.csdn.net/silent_gods/article/details/84455122
(3)令牌问题
设有两个生产者进程A、B和一个销售者进程C,他们共享一个无限大的仓库,生产者每次循环生产一个产品,然后入库供销售者销售;销售者每次循环从仓库中取出一个产品进行销售。如果不允许同时入库,也不允许边入库边出库;而且要求生产A产品和B产品的件数满足以下关系:-n<=A的件数-B的件数<=m,其中n、m是正整数,但对仓库中A产品和B产品的件数无上述要求。
// A-B<=m B-A<=n
// 若只生产A,而不生产B,则A产品最多可生产m次便被阻塞
// 若只生产B,而不生产A,则B产品最多可生产n次便被阻塞;
// 每生产一次A,生产产品B的机会也多一次;同理,每放入一次B,生产产品A的机会也多一次
semaphore mutex=1; // 互斥信号量
semaphore S=0; // 当前仓库中的产品数
semaphore SA=m; // 当前允许A生产的产品数
semaphore SB=n; // 当前允许B生产的产品数
LA=m LB=n
PA(){
while(1){
P(SA);
生产一个产品A;
V(SB);
P(mutex);
产品A入库;
V(mutex);
V(S);
}
}
PB(){
while(1){
P(SB);
生产一个产品B;
V(SA);
P(mutex);
产品B入库;
V(mutex);
V(S);
}
}
PC(){
while(1){
P(S);
P(mutex);
取走一个A或B产品;
V(mutex);
销售产品;
}
}
// 思考:如果仓库中产品数也要满足该关系呢?
(4)理发师问题
一个理发店由一个有N张沙发的等候室和一个放有一张理发椅的理发室组成。没有顾客要理发时,理发师便去睡觉。当一个顾客走进理发店时,如果所有的沙发都已被占用,他便离开理发店;否则,如果理发师正在为其他顾客理发,则该顾客就找一张空沙发坐下等待;如果理发师因无顾客正在睡觉,则由新到的顾客唤醒理发师为其理发。在理发完成后,顾客必须付费,直到理发师收费后才能离开理发店。
int count=0; // 沙发上人数
semaphore mutex; // 实现不同顾客对count的互斥共享
semaphore empty=1,full=0; // 理发椅是否空闲
semaphore payment=0,receipt=0; // 等待付费、收费
guest(){
P(mutex);
if(count>=N){
V(mutex);
离开理发店;
}else{
count++;
V(mutex);
在沙发等待;
P(empty); // 等待理发椅变空
离开沙发,坐到理发椅上;
P(mutex);
count--;
V(mutex);
V(full); // 唤醒理发师
理发;
付费;
V(payment); // 通知理发师收费
P(receipt); // 等待理发师收费
V(empty); // 离开理发椅
离开理发店;
}
}
Barber(){
while(1){
P(full); // 等待理发椅来人
给顾客理发;
P(payment); // 等待顾客付费
收费;
V(receipt); // 通知顾客已收费
}
}
(5)独木桥问题
同一方向的行人可连续过桥,当某一方向有人过桥时,另一方向的行人必须等待;当某一方向无人过桥时,另一方向的行人可以过桥。
int countA=0, countB=0; // 分别表示A、B两个方向过桥的人数
semaphore mutex=1; // 不同方向行人互斥过桥
semaphore mutexA=1, mutexB=1; // 分别实现对countA、countB的互斥访问
PA(){
while(1){
P(mutexA);
if(countA==0) P(mutex); // 第一个过桥
countA++;
V(mutexA);
过桥;
P(mutexA);
countA--;
if(countA==0) V(mutex); // 最后一个过桥
V(mutexA);
}
}