操作系統-進程管理2(進程的互斥與同步)

操作系统-进程管理2(进程的同步与互斥)

  1. 进程的同步与互斥
  • 两个或两个以上的进程不能同时使用的资源称为临界资源。临界资源的存在带来了进程之间的互斥访问的问题。
  • 进程互斥:逻辑上完全独立、毫无关系的两个进程因为竞争同一块资源而相互制约,称为进程互斥。
  • 进程同步:有协作关系的进程不断调整它们之间的相对速度或执行过程,以保证临界资源的合理利用和进程的顺利执行。一般借由中间媒体实现:如信号量操作加锁操作等。同步机制应遵循的规则:
    • 空闲让进
    • 忙则等待
    • 有限等待:进程等待进入临界区的时间必须是有限的,避免进入忙等状态
    • 让权等待:进程不能进入自己的临界区时,应立即释放处理机。
  • 锁机制
    • 上锁与开锁

      锁机制采用锁变量w表示临界区是否上锁。w=1表示已上锁

      高效率的上锁与开锁原语为:

      //加锁原语
      Lock w()
      {
          while (w == 1) { //表示当前进程进入不了临界区
              保护当前进程的CPU现场;
              将当前进程放入w的等待队列,将该进程置于"等待"状态;
              转进程调度;
          }
      }
      
      //开锁原语
      Unlock() {
          if (w等待队列不空) {
              移出等待队列首元素;
              将该进程置于就绪状态,并放入就绪队列;
          }
          w = 0;
      }

      所有要访问临界区的进程必须先执行上锁原语,上锁原语顺利通过,则进程可进入临界区;在完成对临界区的访问后,则执行开锁原语,释放该临界资源。

  • 信号量机制

    信号量机制中申请和释放临界资源的原语为操作为wait操作和signal操作,也被称为P操作和V操作。信号量:在信号量同步机制中用于实现进程的同步与互斥的有效数据结构。常见的有整型信号量、记录型信号量、AND型信号量及信号量集

    • 整型信号量

      整型信号量s表示当前可用的该类临界资源的数量:

      s > 0:系统中空闲的该类临界资源的数量

      s = 0:系统中临界资源数量为0,且没有进程在等待

      s < 0:s的绝对值表示系统中等待的进程的数量

      wait(s):
          while (s <= 0) {
              该进程等待;
              s--;
          }
      
      signal(s): s++;
    • 记录型信号量

      记录型信号量数据结构为:

      struct semaphore{
          int value;
          struct PCB *queue;
      };

      value的值表示系统可用的临界资源的数量,而queue为进程链表指针,指向等待该类资源的PCB队列。

      记录型信号量的原语操作为:

      semaphore S;
      
      //wait操作
      wait(S) {
          S.value--;
          if (S.value >= 0) {
              本进程申请到资源,继续执行;
          }
          else{
              调用block原语,将本进程加入阻塞队列,保护CPU现场,释放处理机资源;
              转进程调度;
          }
      }
      
      //signal操作
      signal(S) {
          S.value++;
          if (S.value <= 0) {//说明PCB队列还有其它进程在等待
              在queue唤醒一个阻塞态进程;
          }
          释放本进程占用的该临界资源,继续执行;
      }
  1. 进程同步问题举例
  • 例7.1 同步使用打印机

    semaphore s;
    s.value = 1;
    void main(){
        parbegin(p1,p2,p3,..,pn);
    }
    pi(){ //i = 1,2,3,...,n
        wait(s);
        打印;
        signal(s);
    }
  • 例7.2 有一个缓存区,供多个进程共享,这些进程中有读进程和写进程。写一个多个进程使用同一个缓存区实现进程同步的程序。
    semaphore empty,full;
    empty.value = 1; //empty用来表示缓存区是否是已被写入的状态
    full.value = 0; //full表示缓存区是否是已被读出的状态。
    
    reader() {
        while (true) {
            wait(full); //读之前先使full置于value为0的状态,避免其它进程也进入读取
            读缓存区;
            signal(empty); //读完后置empty的value为0,表示缓存区的数据已经读完了,可以继续写入了。
        }
    }
    
    writer() {
        while (true) {
            wait(empty);
            写缓存区;
            signal(full);
        }
    }
    
    //通过设置两个信号量实现了writer和reader的交替执行
    void main() {
        prebegin(writer,reader);
    }
  • 例7.3 生产者-消费者问题:生产者进程生产产品,放入容量为n的缓存区供消费者拿走。消费者不能上空缓存区拿东西,生产者不能上满的缓存区放东西。这个与上个文件读写的例子有些类似。
    /*
    用一个数组表示具有n个缓存区的缓存池。设有输入指针in指向一个可存放产品的缓存区,输出指针out指向可取得产品的缓存区。由于数组可以循环放置,所以当输入或输出加一时,可表示为: in = (in + 1) % n, out = (out + 1) % n。当(in + 1) % n = out时,表示缓存池已满,当in = out时,表示缓存池已空。整型counter表示缓存池中满缓存区的数量。
    还有以下变量:
    mutex:互斥使用缓存池信号量,初值mutex = 1
    empty:空缓存区的信号量
    full:满缓存区的信号量
    */
    semaphore mutex, empty, full;
    mutex.value = 1;
    empty.value = n;
    full.value = 0;
    
    product buffer[n];
    int in = 0,out = 0;
    
    void main() {
        prebegin(producer, consumer);
    }
    void producer() {
        while (true) {
            生产一件产品;
            wait(empty);
            wait(mutex);
            将产品放入缓存区;
            counter++;
              in = (in + 1) % n;
            signal(mutex);
            signal(full);
        }
    }
    void consumer() {
        while (true) {
            wait(full);
            wait(mutex);
            拿走一件产品;
            counter--;
            out = (out + 1) % n;
            signal(mutex);
            signal(empty);
        }
    }
    //注意:在这两个进程中两个wait()信号量的顺序不能改变,必须先要申请到full资源或empty资源才能继续申请mutex的资源,否则可能会造成申请到mutex的资源但却申请不到full或empty的资源的情况,然后进程就会进入等待状态,使得signal(mutex)不能执行,造成缓存池的锁死。

    这个问题比较有代表性,一般把系统中使用同一类资源的进程称为该资源的消费者,释放该类资源的进程称为生产者。

  • 例7.4 读者-写者问题:文件F可以被多个进程共享,向F中写的称为写进程,读取F的称为读进程。用wait和signal解决进程间的同步问题。
    //F可以同时被多个进程读,但不能被多个进程同时写,否则会造成数据的混乱.或者说一个写进程会对其他所有进程造成排斥。
    semaphore wmutex,rmutex;
    wmutex.value = 1;
    rmutex.value = 1;
    int readcount = 0; //正在进行读操作的进程数量,因为readcount是一个会被多个读进程访问的资源,所以上文设置了rmutex来控制访问。
    void main() {
        prebegin(writer,reader);
    }
    void writer() {
        while (true) {
            wait(wmutex);
            写操作;
            signal(wmutex);
        }
    }
    void reader() {
        while (true) {
            wait(rmutex); //要想访问readcount必须先申请资源。
            if (readcount == 0) { //如果没有同类型进程在访问该资源,则需要进行申请
                wait(wmutex);
            }
            readcount++;
            signal(rmutex);
            读操作;
            wait(rmutex);
            readcount--;
            if (readcount == 0) signal(wmutex);
            signal(rmutex);
        }
    }

    这个问题也是一类问题的典型代表,不同于生产者-消费者问题,这种模式允许任意多个有特定行为的进程进入,但不允许其他类型进入。即同类型进程之间不存在互斥现象。解决这一问题的关键就是当有至少一个同类型的进程正在访问该资源时,本进程便可以不必进行资源申请,直接访问该资源。

  • 例7.5 哲学家进餐问题:五个哲学家围着一张餐桌吃饭,桌上有5支筷子,在每个人之间放一支。哲学家只有拿到了左右两支筷子才能进餐,没有拿到则只有等到别人吃完才能拿到。每个哲学家在吃到东西之前不会放下手里的筷子。试描述哲学家吃饭的过程。

    假设每一位哲学家拿筷子的方法都是先拿左边的,再拿右边的。则第i位哲学家的拿筷子过程可描述为:

    //每一根筷子都是临界资源,为此设立一个筷子信号量数组
    semaphore chopstick[5];
    //每根筷子的初始值为1,筷子i相邻筷子的索引为(n+i-1)%n 和(i+1)%n。设哲学家i位于筷子i的右边
    void main() {
        prebegin(p1(),p2(),p3(),p4(),p5());
    }
    void pi() {   //p表示哲学家的吃饭过程
      while (true) {
            wait(chopstick[i]);
            wait(chopstick[(i + 1) % n]);
            吃饭;
            signal(chopstick[(i + 1) % n]);
            signal(chopstick[i]);
        }
    }

    但是这种做法会造成一个问题,即所有哲学家同时拿起了左边的筷子,导致没有哲学家能拿到右手的筷子。造成了死锁

    解决死锁的方法有多种,如:

    1).仅当哲学家的左右手的筷子均可用时才允许拿起筷子

    2).最多允许n - 1个哲学家同时去拿左边的筷子,保证总有一个哲学家能够拿到一双筷子。

原文地址:https://www.cnblogs.com/lunar-ubuntu/p/12233515.html

时间: 2024-10-08 15:00:23

操作系統-進程管理2(進程的互斥與同步)的相关文章

操作系統3-內存管理(分區存儲和頁式存儲)

操作系統3-內存管理(分區存儲和頁式存儲) 2. 分區存儲管理方式 分區管理的基本思想是:將內存空間氛圍一個或若干個連續的區域,稱為分區.每個分區可以存放一個獨立的用戶程序.分區的特點是一個程序可以連續地加載內存. 分區可以分為:單一分區.固定分區.可變分區和重定位分區. 2.1 單道程序的連續分配 單道程序的連續分配方式將內存分為系統區和用戶區,只能用於單用戶.單任務的操作系統. 系統區 系統區僅供操作系統使用,一般駐留在內存的低地址區,其中包括中斷向量.中斷向量是操作系統的核心功能模塊加載內

操作系統3-內存管理(頁面置換算法)

操作系統3-內存管理(頁面置換算法) 7. 頁面置換算法 在上一節講過, 換入換出頁面要根據特定的算法來執行, 這種算法就是頁面置換算法. 不合適的算法可能會使系統發生抖動,所謂抖動即指剛剛換出的頁面又要換回來,換回來不久又要換出去,這樣就導致系統的大部分工作時間都花在了頁面調度上,導致效率不高. 下面是幾種常見的頁面置換算法: 7.1 先入先出頁面置換算法 顧名思義,根據隊列的數據結構的思想,總是將內存存在最久的頁面先換出. 7.2 最近最久未使用頁面置換算法(Least Recently U

操作系統3-處理機調度與死鎖(死鎖)

操作系統-處理機調度與死鎖3(死鎖) 7.死鎖問題 死鎖是指多個進程等待其它進程佔有的資源,因而無限期等待下去的局面. 系統發生死鎖時,一定具備以下四個條件: 互斥條件.對於一個排他性資源,某一時刻最多允許一個進程佔有. 佔有且申請條件.進程至少已佔有一個資源,又要申請新的資源.此時該進程阻塞,且在等待過程中不釋放已經佔有的資源. 不可搶佔條件.進程獲得的資源在未使用之前,其他進程不得搶佔該資源. 環路條件.若干個進程相互要佔有彼此的資源,形成一個環路. 8.死鎖的避免 要避免死鎖,分為靜態策略

操作系統-進程管理4(線程)

操作系统-进程管理(线程) 线程 线程的基本概念 线程是比进程更小的.能够独立运行的基本单位,线程比进程能更好地提高程序的并行执行速度,充分利用多处理机的优越性.引用线程主要是为了提高系统的处理效率,减少处理机的空转时间和进行调度时因保护CPU现场浪费的时间. 线程是进程中执行运算的最小单位,即执行处理机调度的基本单位.在引入线程的操作系统中,可以在一个进程内部进行线程的切换. 进程是资源分配的基本单位,同一进程的所有线程共享该进程的所有资源.线程是分配处理机的基本单位,真正在处理机上运行的是线

幾個步驟輕鬆在windows操作系統上搭建GO語言開發環境

position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流

第三章 進程管理

可以參考<深入Linux內核架構>第二章閱讀筆記. 1. 進程 process 程序本身並不是進程,進程是處於執行期的程序以及相關的資源的總稱.如:可執行代碼段.打開的文件.掛起的信號.內核內部數據.處理器狀態.一個或多個具有內存映射的內存地址空間以及一個或多個執行線程.存放全局變量的數據段等等. 實際上,進程就是正在執行的程序代碼的實時結果. 進程的另一個名字是任務(task) 2. 現代操作系統提供的兩種虛擬機制 虛擬處理器:讓正在分享同一個處理器的多個進程都覺着自己在獨享處理器 虛擬內存

作業系統的類型

依處理方式而分 整批處理作業系統(Batch processing OS) 處理方式:將欲處理的資料或程式整批集中,置於如卡片.紙帶.磁帶.磁碟等儲存在媒體內,當要處理時,CPU才會到媒體中讀取資料後加以處理. 優點:整批處理作業系統是第一代作業系統,比起沒有作業系統時,更有效地改進了電腦的作業效率,減少大部份人工操作的比率. 缺點:因為CPU速度遠較存取資料的I/O為快,所以此方式CPU常被閒置,效率低. 分時作業系統(Time-sharing OS) 處理方式:CPU每次分配給各程序式(pr

使用 NIO.2 操作檔案系統

Java 一直到 JDK 1.3 為止,都是使用 java.io 下的類別進行 I/O 的處理,對這有興趣的鄉民,可以參考「Java I/O」,那是我 13 年前整理的 ... XD.JDK 1.4 之後提供了 NIO,到了 JDK 1.7 又加上些新的功能,稱為 NIO.2,這些類別都被放在 java.nio 下,一般來說,使用 java.nio 類別操作檔案系統,會比使用 java.io 效率來的高且方便. 在進入主題前,各位不妨先看一下我之前整理的「Working with the Pat

Linux-PAM(Linux下的密碼認證和安全机制)系統管理員指南(中文版)

he Linux-PAM 系统管理员指南作者:Andrew G. Morgan, [email protected]翻译:孙国清(Thomas Sun),[email protected]DRAFT v0.71 1999/11/8 这个文档所涉的是系统管理员须知的关于Linux-PAM库的知识. 它涉及了设置PAM的正确语法并讨论维护一个可靠系统的正确的策略.1. 介绍 Linux-PAM (Linux下的可插入式认证模组) 是一套共享函数库,允许系统管理员来决定应用程式如何识别用户. 换句话说