zoukankan      html  css  js  c++  java
  • 操作系统学习笔记(六)-- 进程间同步

    最近开始学习操作系统原理这门课程,特将学习笔记整理成技术博客的形式发表,希望能给大家的操作系统学习带来帮助。同时盼望大家能对文章评论,大家一起多多交流,共同进步!

    本文主要分以下几个方面:

    • 临界区/段问题
    • 硬件机制保证同步
    • 信号量
    • 经典的同步问题
    • 管程(Monitors)

    背景:数据并发访问共享的数据 => 不确定性/不一致性

       保持数据的一致性    => 有序的执行协作进程

    并行:某一时刻多个进程同时运行;  并发(Coccurrent):某一时间段多个进程同时运行

    应对共享的变量采用互斥操作。

    临界区:一次只能被一个进程使用的资源被称为临界资源(Critical Resource),进程使用临界资源代码段称为临界区/段。

    应在共享的变量和数据结构或者慢速设备资源上使用互斥。

    分为四个区:进入区(Entry section) 用于判断共享资源是否被访问,临界区(Critical section),退出区(Exit section) 用于取消互斥,剩余区(Remainder section),非共享或非互斥的资源区。

    临界区的使用原则:

    1. 互斥:智能互斥,不能共享。 (忙则等待)
    2. 空闲让进
    3. 有限等待
    4. 让权等待,禁止busy waiting

    通过硬件指令在执行过程中不会被中断。

    信号量机制(Semaphore)

    好处: 1. 复杂度很低;  2. 消除忙等

    信号量S为整型变量,可用wait()和signal()两种原语的标准方式修改S。

    wait()用于申请资源。

    wait(s){
        while s <= 0
           ;   //no-op
         s--;     
    }
    

     signal()用于释放资源。

    signal(s){
       s++;
    }
    

     信号量的类型:计数型信号; 二元信号量(0,1),用于互斥锁。

    物理意义:

    wait()用于申请资源,执行value--,如果value<0则表示已无该类资源,则将该进程放入等待S的队列中阻塞。|value|表示等待S的进程数(value<0时)。

    signal()用于释放资源,执行value++,如果value<=0,表示有等待进程,用一定的算法唤醒进程之一。

    死锁和饥饿(Deadlock and Starvation)

    死锁表示系统由于资源调度不合理而导致的僵局,死锁时系统处于饥饿状态。

    死锁时CPU没事做;死循环时CPU不停运算。

    有界缓存问题(Bounded-Buffer Problem)/生产者-消费者问题

    • N个缓冲区,每个能存放一个资源
    • 互斥信号量初值为1
    • 满信号量初值为0(已放资源的缓冲区量)
    • 空信号量初值为N(未放资源的缓冲区量)

    分析:

    缓冲  共享 -> 互斥 mutex = 1

    前趋  P -> C  缓冲区全空,C受制于P,full信号量是否大于零(full < 0)

        C -> P  缓冲区全满,p受制于C,empty信号量是否大于零(empty < 0)

    The strcture of the producer process

    while(true){
        // produce an item
        wait(empty);
        wait(mutex);
    
        // add the item to the buffer
    
        signal(mutex);
        signal(full);
    }

    The structure of the consumer process

    while(true){
        wait(full);
        wait(mutex);
    
        // remove an item from buffer
    
        signal(mutex);
        signal(empty);
    
        // consume the removed item
    }

    读者-写者问题(Readers-Writers Problem)

    一组数据集被一系列进程所共享

    • 读者--只能读数据集
    • 写者--能读且能写

    互斥信号量mutex=1,保证readcount被正确更新

    写信号量wrt=1

    整型量readcount被初始化为0

     1 Semaphore mutex,wrt := 1,1;
     2 Integer readcount := 0;
     3 begin
     4     parbegin
     5         reader                                    writer
     6             while(true){                            while(true){
     7                 wait(mutex);                            wait(wrt);
     8                 readcount++;
     9                 if(readcount==1) wait(wrt);                // waiting
    10                 signal(mutex);
    11                                                         signal(wrt);
    12                 // reading is performed                }
    13 
    14                 wait(mutex);
    15                 readcount--;
    16                 if(readcount==0) signal(wrt);
    17                 signal(mutex);
    18             }
    19     parend
    20 end

    哲学家进餐问题(Dining-Philosophers Problem)

    The structure of Philosopher i:

     1 while(true){
     2     wait(chopstick[i]);
     3     wait(chopstick[(i+1)%5]);
     4 
     5     //eat
     6 
     7     signal(chopstick[i]);
     8     signal(chopstick[(i+1)%5]);
     9 
    10     //think
    11 }

    该算法存在死锁问题!!!

    避免死锁问题:

    • 允许最多四个哲学家同时吃饭(当桌上有五只筷子时),添加互斥量mutex=4,在吃之前执行wait(mutex),吃之后执行signal(mutex)
    • 同时wait操作,即同时拿起筷子,在两次wait操作之间不可中断 => swait(s1,s2)
    • 给哲学家按顺时针或逆时针排序,序号为奇数的先拿左边筷子再拿右边筷子。序号为偶数的先拿右边筷子再拿左边筷子(或相反)

    管程(monitor) -- 秘书进程

     进程间通信的另一实例:理发师睡觉问题(The Sleeping-Barber Problem)

    • Barbershop consists of a waiting room with n chairs, and a barber room with one barber chair;
    • No customers, barber goes to sleep;
    • If barber is asleep, new customers wakes up him.
     1 Var Semephore empty, full, mutex := n, 0, 1;
     2 begin
     3     parbegin
     4         Customer:                        Barber:
     5             begin                            begin
     6                 repeat                            repeat
     7                     wait(empty);                    wait(full);
     8                     wait(mutex);                    signal(empty);
     9                         // find a seat;                    // cutting
    10                     signal(mutex);                until false
    11                     signal(full);            end
    12                 until false
    13             end
    14     parend
    15 end

    该算法未解决顾客来了之后发现没位置离开的情况;

     1 Var Semephore customers, barber, mutex := 0, 0, 1;
     2 Var int waiting := 0;
     3 begin
     4     parbegin
     5         Customer:                        Barber:
     6             begin                            begin
     7                 wait(mutex);                    repeat:
     8                 if(waiting < n){                    wait(customers);
     9                     waiting++;                        wait(mutex);
    10                     signal(customers);                waiting--;
    11                     signal(mutex);                    signal(mutex);
    12                     wait(barber);                        // cutting
    13                 }                                    signal(barber);
    14                 else signal(mutex);                until false    
    15             end
    16     parend
    17 end
  • 相关阅读:
    Ext.Net多表头跨行跨列
    操作文件
    HighMaps
    HighCharts动态读取显示
    SAP CRM 项目笔记(一) SOW(工作说明书)讨论
    .net 动态编译解决考勤计算问题
    CPU的大小端模式
    将一个数转化为任意进制的数
    关于内存对齐
    常量指针与指针常量
  • 原文地址:https://www.cnblogs.com/PaulingZhou/p/5343166.html
Copyright © 2011-2022 走看看