进程同步问题总结

生产者-消费者问题类

  1. 由三个进程get,copy和put以及两个缓冲区buffer1和buffer2完成一项输入/输出操作。进程get的功能是把一张卡片上的信息从读卡机上读进buffer1;进程copy的功能是把buffer1中的信息复制到buffer2;进程put的功能是取出buffer2中的信息并从打印机上打印输出。试用P、V操作完成这三个进程间的尽可能并发正确执行的关系(用程序或框图表示),并指明信号量的作用和初值。
    分析:可设置6个信号量mutex1,mutex2,empty1,empty2,full1,full2。
    mutex1和mutex2是互斥信号量,初值为1,分别用于对buffer1和buffer2的互斥访问;
    empty1和empty2为同步信号量,初值为1,分别表示buffer1和buffer2是否空闲,1表示空闲,0表示不空闲;
    full1和full2为同步信号量,初值为0,分别表示buffer1和buffer2中是否有可取用的信息,1表示有可取用的信息,0表示无可取用的信息。
    semaphore mutex1, mutex2, empty1, empty2, full1, full2 ;
    mutex1=mutex2=1;		//互斥信号量
    empty1=empty2=1;		//生产者进程的同步信号量
    full1=full2=0;		//消费者进程的同步信号量
    
    parbegin
    	process get( )  //读进程(生产者进程)
    	{
          
          
    		while (1) {
          
          
    			从读卡机读入一张卡片的信息;
    			P(empty1);	//看看buffer1是否空闲
    			P(mutex1);	//互斥访问buffer1
    			将信息放入buffer1;
    			V(mutex1);
    			V(full1);	//通知进程copy,buffer1中已有信息可取(若copy正在等待,则唤醒之)
    		}
    	}
    	
    	process copy( )  //复制进程(既是消费者又是生产者进程)
    	{
          
          
    		while (1) {
          
          
    			P(full1)	//看看buffer1是否有信息可取
    			P(mutex1); 	//互斥访问buffer1
    			从buffer1中复制出信息;
    			V(mutex1);
    			V(emtpy1); 	//通知get,buffer1中的信息已取走(可能唤醒get)
    			P(empty2);	//看看buffer2是否空闲
    			P(mutex2);	//互斥访问buffer2
    			将复制的信息放入buffer2;
    			V(mutex2);
    			V(full2);	//通知put,buffer2中已有信息
    		}
    	}
    	
    	process put( ){
          
          		//输出进程(消费者进程)
    		while (1) {
          
          
    			P(full2);		//测试buffer2中是否有信息
    			P(mutex2);	//互斥访问buffer2
    			从buffer2中取出信息;
    			V(mutex2);
    			V(empty2);	//通知copy,buffer2中的信息已取走
    		}
    	}
    parend
    
  2. 若一只盘子一次只能放一个水果,A只往盘中放苹果,B只往盘中放梨子,C只从盘中取苹果,D只从盘中取梨子。试用:(1) 信号量和P、V操作;(2) 管程,写出同步算法。
    采用P、V操作的同步算法如下:
    semaphore SAB=1;   //A、B的资源信号量,同时又是它们的互斥信号量
    semaphore SC=0;    //C的资源信号量(用于与A同步)
    semaphore SD=0;    //D的资源信号量(用于与B同步)
    
    begin
    	parbegin
    	process A:      //进程A的算法描述
    	{
          
          
    		while(true) {
          
          
    			取一个苹果;
    			wait(SAB);    //测试盘子是否为空
    			将一苹果放入盘中;
    			signal(SC)    //通知C盘中已有苹果(可能唤醒C)
    		}
    	}
    	process C:
    	{
          
          
    		while(true) {
          
          
    			wait(SC);    //测试盘子是否有苹果
    			从盘中取出苹果;
    			signal(SAB);    //通知A(或B)盘子已经空(可能唤醒A或B)
    			消费该苹果;
    		}
    	}
    	process B:      //进程B的算法描述
    	{
          
          
    		while(true) {
          
          
    			取一个梨子;
    			wait(SAB);    //测试盘子是否为空
    			将一梨子放入盘中;
    			signal(SD)    //通知D盘中已有梨子(可能唤醒D)
    		}
    	}
    	process D:
    	{
          
          
    		while(true) {
          
          
    			wait(SD);    //测试盘子是否有梨子
    			从盘中取出梨子;
    			signal(SAB);    //通知A(或B)盘子已经空(可能唤醒A或B)
    			消费该梨子;
    		}
    	}
    	parend
    end
    
    采用管程的同步算法如下:
    首先定义管程MPC,该管程可描述如下:
    type MPC=monitor
       var flag: integer;	//flag=0:盘中无水果;=1盘中有苹果;=2盘中有梨子
       empty: condition;	//用于A或B等待空盘子
       W: array[1..2] of condition	//W[1]用于等待苹果,W[2]用于等待梨子
       
       procedure entry put(integer k)
         begin
    		if flag>0 then empty.wait; //生产者A或B进程阻塞
    		flag=k;
    		放一k号水果入盘中;	//设1号水果为苹果,2号水果为梨子
    		if W[k].queue then full.signal;  //若有等待k号水果者,则唤醒之
         end
         
      procedure entry get(integer k)
         begin
             if flag<k then W[k].wait;	//消费者C或D进程阻塞
            从盘中取k号水果;
             flag := 0;
             if empty.queue then empty.signal;  //若等待队列非空,则唤醒队首的一个生产者进程
      	 end
       
    begin
       flag :=0;  //初始化内部数据
    end
    
    A、B、C、D四个进程的同步算法可描述如下:
    parbegin
    	Process A
    		begin
    			任取一个苹果;
    			MPC.put(1);
    		end
    		
    	Process B
    		begin
    			任取一个梨子;
    			MPC.put(2);
    		end
    		
    	Process C
    		begin
    			MPC.get(1);
    			吃苹果;
    		end
    		
    	Process D
    		begin
    			MPC.get(2);
    			吃梨子;
    		end
    parend
    
  3. 设自行车生产车间有两个货架,货架A可以存放8个车架,货架B可以存放20个车轮;又设有4个工人,他们的活动是重复劳动,分别为:工人1 加工一个车架放入货架A中;工人2、3分别加工车轮放入货架B中(每人每次放入1个车轮);工人4从货架A中取一个车架,再从货架B中取两个车轮,组装成一辆自行车。试用PV操作实现四个工人的合作。
    分析:信号量Aempty表示货架A的空位数,其初值为8;信号量Afull表示货架A上存放的车架数,其初值为0;信号量Bempty表示货架B的空位数,其初值为20;信号量Bfull表示货架B上存放的车轮数,其初值为0;信号量mutex用于互斥(初值为1)
    BEGIN
    semaphore Aempty,Bempty,Afull,Bfull,mutex;
    Aempty := 8;Bempty := 20;Afull := 0;Bfull := 0;mutex :=1;
    
    PARBEGIN
    	Worker1:BEGIN
    		L1:生产1个车架;
    		P(Aempty);		//测试货架A是否有空位置
    		P(mutex);			//互斥使用货架A
    		车架放到货架A;
    		V(Afull);			//货架A上的车架数增1,必要时唤醒等待的进程
    		V(mutex);
    		goto L1;
    	END
    	
    	Worker2、3:BEGIN
    		L2:生产1个车轮;
    		P(Bempty);		//测试货架B是否有空位置
    		P(mutex);		//互斥使用货架B
    		车轮放到货架B;
    		V(Bfull);		//货架B上的车轮数增1,必要时唤醒等待的进程
    		V(mutex);
    		goto L2;
    	END
    	
    	Worker4:BEGIN
    		L3:P(Afull);				//测试货架A上是否有车架
    		P(Bfull);P(Bfull);	//测试货架B上是否有2个车轮
    		P(mutex);
    		取1个车架;取2个车轮;
    		V(Aempty);			//货架A空位置增1
    		V(Bempty);V(Bempty);//货架B空位置增2
    		V(mutex);
    		组装成一辆自行车;
    		goto L3;
    	END
    PAREND
    END
    

读者-写者问题

  • 读者优先:为实现对共享文件的互斥访问,设置互斥信号量rw,初值为1;再设置一个整型变量count表示正在读的进程数目。
  • 但这时有一个问题:第一个读进程进来时,需要对共享文件进行加锁,即if(count == 0) P(rw);,然后count++,这时第二个读进程进来,会触发P(rw),那么读进程便无法执行下去。
  • 为此需要设置一个互斥信号量mutex来保证各个读进程对count的互斥访问
    semaphore rw = 1, mutex = 1;
    int count = 0;
    
    void reader(){
          
          
    	while(TRUE){
          
          
    		wait(mutex);//保护count共享变量,在第二个读进程进来时,不会触发if判断
    		if(count == 0) wait(rw);//第一个读进程到达时,写进程不能进行
    		count++;
    		signal(mutex);
    		...
    		读文件
    		...
    		wait(mutex);
    		count--;
    		if(count == 0) signal(rw);//保证最后一个读进程读完时,释放rw
    		signal(mutex);
    	}
    }
    
    void writer(){
          
          
    	while(TRUE){
          
          
    		wait(rw);
    		写文件
    		signal(rw);
    	}
    }
    
  • 写者优先:一旦有写者到达,后续的读者必须等待。增加一个信号量,在写进程到达时封锁后续读进程
    	semaphore rw = 1, mutex = 1, w = 1;
    	int count = 0;
    	
    	void reader(){
          
          
    		while(TRUE){
          
          
    			wait(w);
    			wait(mutex);//保护count共享变量,在第二个读进程进来时,不会触发if判断
    			if(count == 0) wait(rw);//第一个读进程到达时,写进程不能进行
    			count++;
    			signal(mutex);
    			signal(w);
    			...
    			读文件
    			...
    			wait(mutex);
    			count--;
    			if(count == 0) signal(rw);//保证最后一个读进程读完时,释放rw
    			signal(mutex);
    		}
    	}
    	
    	void writer(){
          
          
    		while(TRUE){
          
          
    			wait(w);
    			wait(rw);
    			写文件
    			signal(rw);
    			signal(w);
    		}
    	}
    

猜你喜欢

转载自blog.csdn.net/weixin_44863537/article/details/109393368