• 操作系统进程同步习题记录


    BUAA操作系统进程同步的一些作业,由于格式问题,可能有些代码缩进过度,语法没什么问题
    有关读者写者问题的分析单独做写了一篇:传送门

    奇偶数生产者-消费者问题

    三个进程 P1、P2、P3 互斥使用一个包含 N(N>0)个单元的缓冲区。

    P1 每次用 produce()生成一个正整数并用 put()送入缓冲区某一个空单元中;

    P2 每次用 getodd()从该缓冲区中取出一个奇数并用 countodd()统计奇数个数;

    P3 每次用 geteven()从该缓冲区中取出一个偶数并用 counteven()统计偶数个数。

    请用信号量机制实现这三个进程的同步与互斥活动, 并说明所定义的信号量的含义。

    答:想象P1为生产者,P2、P3为消费者。

    P1、P2共享缓冲区的奇数部分,故设置同步信号量odd;

    P1、P3共享缓冲区的偶数部分,故设置同步信号量even;

    P1、P2、P3共享整个缓冲区,用一个互斥mutex来保护,再设置同步信号量empty,表示缓冲区空位资源。

    伪代码如下:

    #define N 100
    Semaphore empty = N;  // 假设初始条件下缓冲区有N个空位
    Semaphore mutex = 1;
    Semaphore odd = 0;
    Semaphore even = 0;
    
    void P1(){
      int integer;
      while(true){
        integer = produce(); 	// 生成一个整数
        P(empty); 						// down(empty),若empty为0则会被阻塞(等待别人拿走)
        P(mutex);							// 开始互斥,down(mutex)
        put();								// 放入缓冲区
        V(mutex);							// 访问临界区结束,up(mutex)
        if(integer %2 == 0){
          V(even);						// 是偶数
        } else {
          V(odd);							// 是奇数
        }
      }
    }
    
    void P2(){
      while(true){
        P(odd);							// 请求一个奇数,down(odd)
        P(mutex);						// 互斥
        getodd();
        V(mutex);
        V(empty);						// 缓冲区多一个位置,up(empty)
        countodd();
      }
    }
    
    void P3(){
      while(true){
        P(even);						// 请求一个偶数,down(even)
        P(mutex);						// 互斥
        geteven();
        V(mutex);
        V(empty);						// 缓冲区多一个位置,up(empty)
        counteven();
      }
    }
    

    野人吃肉

    一个野人部落从一个大锅中一起吃炖肉,这个大锅一次可以存放 M 人份的炖肉。

    当野人们想吃的时候,如果锅中不空,他们就自助着从大锅中吃肉。如果大锅空了,他们就叫 醒厨师,等待厨师再做一锅肉。

    答:野人和厨师共享缓冲区锅,设置互斥信号量mutex;

    厨师一次性往锅里放M份肉,设置厨师信号量cook,整形变量meat记录剩下的肉数量。

    野人没吃完时,厨师在睡觉,设置野人信号量wild;

    当大锅空的时候,野人不能够调用 getServingFromPot() ;

    仅当大锅为空的时候,大厨才能够调用 putServingsInPot()

    #define M 100
    Semaphore mutex = 1;
    Semaphore cook = 0, wild = 0;
    int meat = 0;
    void wildman(){
       while (true){
        P(mutex);
    	if (meat > 0){				// 锅里还有肉
        	getServingFromPot();
      	eat();
            meat = meat - 1;
            V(mutex);						// 吃完一份,释放缓冲区占用
           } 
          else{
            V(wild);						// 唤醒睡觉的厨师
            P(cook);						// 请求一个厨师加肉,若厨师为0则被阻塞(等待煮肉)
            V(mutex);
          }
      }
    }
    
    void Cook(){
      while (true) { 
        P(mutex);
        if (meat == 0){ 			// 煮肉ing
          putServingsInPot(M);
          meat = meat + M;
          V(mutex);
          V(cook);					 	// 厨师做好了,可以唤醒野人等待进程继续吃
        }
        else{
          // 锅里不空,不用煮肉,睡觉(野人为0,没有人叫他,阻塞)
          P(wild);
        }
    	}
    }
    
    

    缓冲区产品

    系统中有多个生产者进程和消费者进程,共享用一个可以存 1000 个产品的缓冲区(初始为空),当缓冲区为未满时,生产者进程可以放入一件其生产的产品,否则等待;

    当缓冲区为未空时,消费者进程可以取走一件产品,否则等待。

    要求一个消费者进程从缓冲区连续取出 10 件产品后,其他消费者进程才可以取产品,请用信号量 P,V 操作实现进程间的互斥和同步,要求写出完整的过程;并指出所用信号量的含义和初值。

    答:生产者可以一直不停地放,除非满了则阻塞,设置同步信号量empty表示空的数量,同步信号量stuff表示产品的数量;

    生产者和消费者共享一个缓冲区,设置互斥信号量mutex;

    有所不同的是,一个消费者必须一次拿1件产品,连续拿10次,读10次缓冲区,该过程不可中断。

    #define N 1000;
    Semaphore mutex = 1;
    Semaphore mutex_get = 1;
    Semaphore empty = N;
    Semaphore stuff = 0;
    
    void producer(){
      while(true){
        P(empty);				// 若empty为0没有空闲则等待
        P(mutex);
        puts();					// 放入一件产品
        V(mutex);
        V(stuff);				// 释放产品,可以唤醒消费者等待拿走
      }
    }
    
    void consumer(){
      int i = 0;
      while(true){
        // 当一个消费者P(mutex)时其他消费者P(mutex)会被阻塞(等待别人拿完)
        P(mutex);				// 占用缓冲区直到拿走10个再释放
        for(i = 0; i < 10; i++){
          P(stuff);			// down(stuff),产品不足会被阻塞
          P(mutex_get);
          gets();				// 取走一件物品
          V(mutex_get);
          V(empty);		  // up(empty)
        }
        V(mutex);				// 释放互斥
      }
    }
    

    寿司店问题

    假设一个寿司店有 5 个座位,如果你到达的时候有⼀个空座位,你可以立刻就坐。但是如 果你到达的时候 5 个座位都是满的有⼈已经就坐,这就意味着这些人都是一起来吃饭的,那么你需要等待所有的⼈一起离开才能就坐。编写同步原语,实现这个场景的约束。

    • 使用整型变量eatingwaiting记录在寿司店就餐和等待的线程,使用信号量mutex对这两个变量的读写进行保护
    • 使用信号量queue表示排队
    • 使用布尔变量must_wait表示寿司店现在满座,新来的顾客必须等待
    int eating = 0, waiting = 0;
    Semaphore mutex = 1, queue = 1;
    bool must_wait = false;
    
    void Customer(){
      P(mutex);
      if (must_wait){
        waiting++;
        V(mutex); //对waiting变量的保护可以释放
        P(queue);	// 被阻塞,坐着等待排队,等待被唤醒
      }
      else {
        eating++;
        must_wait = (eating == 5) 
        // 一旦我是最后一个来坐下吃导致人满的就要等所有人一起吃完,好难过
        V(mutex);	// 对eating变量的保护可以释放
      }
      // 上一部分已经解决了进店后是等待还是吃的问题
      Eat_sushi();// else的人和被唤醒的排队者成功进入这一步
      P(mutex);   // 开启对eating, waiting变量保护
      eating--;		// 吃的人-1,如果5个没全吃完,不可以换下一批人吃
      if (eating == 0){ // 最后一个吃完的人离开才可以进顾客
        int n = min(5, waiting);	// 放顾客进来的数量,不超过5个
        waiting -= n;
        eating +=n;
        must_wait = (eating == 5)
        for(int i = 0; i<n; i++){
          V(queue);  // 唤醒排队的n个人继续进程
      }
      V(mutex);	// 允许下一个吃完的人对变量和队列进行操作
    }
    
    

    搜索-插入-删除问题

    三个线程对一个单链表进行并发的访问,分别进行搜索、插入和删除。搜索线程仅仅读取链表,因此多个搜索线程可以并发。

    插入线程把数据项插入到链表最后的位置;多个插入线程必须互斥防止同时执行插入操作。但是,一个插入线程可以和多个搜索线程并发执行。

    最后,删除线程可以从链表中任何一个位置删除数据。 一次只能有一个删除线程执行;删除线程之间,删除线程和搜索线程,删除线程和插入线程都不能同时执行。

    请编写三类线程的同步互斥代码,描述这种三路的分类互斥问题。

    • 这个问题与读者写者有些类似
    Semaphore insertMutex =1, searchMutex = 1; // 保护int变量
    Semaphore No_search = 1; // 顾名思义,为1时没有搜索进程访问
    Semaphore No_insert = 1; // 为1时没有插入进程访问
    //当上述两个信号量同时为1,删除者才可以进行删除操作
    
    int searcher = 0, inserter = 0;
    void Search(){
      P(searchMutex);
        searcher++;
        if (searcher == 1)	// 第一个进来的搜索者加锁
          P(No_search)
      V(searchMutex);
      Searching(); // 访问临界区,多个搜索无需互斥
      P(searchMutex);
      	searcher--;
      	if (searcher == 0)
          V(No_search);	 // 表示此时没有搜索线程在进行,解锁
      V(searchMutex);
    }
    
    void Insert(){
      P(insertMutex);
      	inserter++;
      	if (inserter == 1)
          P(No_insert)
      V(insertMutex);
      
      P(insertMutex); // 既然可以和搜索线程并行,那么不用管Searcher
      	Inserting();	// 访问临界区,多个插入者要互斥访问,一次一个insert
      V(insertMutex);
      
      P(insertMutex);
      	inserter--;
      	if (inserter == 0)
          V(No_insert); // 解锁,可唤醒删除者
      V(insertMutex);
    }
    
    void Delete(){	  // 删除线程与其他任何线程互斥
      P(No_search);
      	P(No_insert); // 若为1则可进入,这个信号量顺便也可以当作删除者的互斥保护
      		Deleting();	// 搜索和插入线程都没,成功进入临界区
      	V(No_insert);
      V(No_search);	
    }
    
    
  • 相关阅读:
    JPA实体类中常用的注解
    Eclipse的Project Facets属性
    java.util.HashMap的简单介绍
    java.util.Stack(栈)的简单使用
    java.util.Queue(队列)的简单使用
    如何让Spring MVC接收的参数可以转换为java对象
    解决eclipse报PermGen space异常的问题
    HTML <form> 标签的 enctype 属性
    Chrome浏览器查看cookie
    Eclipse调试时出现source not found的问题
  • 原文地址:https://www.cnblogs.com/vanellopeblog/p/process_syn.html
Copyright © 2020-2023  润新知