电子科技大学 820 PV 题


写在前面:
转载请注明本文链接: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);
    }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM