操作系统——Process Synchronization

211复习资料

1. 背景

让进程同步/一部执行,同时发生的access会导致data inconsistency。要保证cooperating processes 的执行顺序。

  • eg. producer-consumer模型用count计数会遇到race condition

2. Critical Section Problem

  • n processes{p0,p1,p2...pn-1},每个process都有critical section。
  • 每个进程都要ask permission in entry section进入critical section
  • 每个进程都要exit section再进入remainer section
  • do{
        entry section
           critical section
        exit section
           remainder section  
    }

     

  • 三个要求:mutual exclusion: if process Pi is excuting in its critical section then...
    •    progress: if no process is executing in its critical section and there exist some processes that wish to enter their critical section...
    •         bounded waiting: the number of times that other processes are allowed to enter their critical sections...
  • 两个方法:preemptive(real time sys) and non preemptive(free of race conditions in kernel mode)
  • Peterson's Solution:
    • load/store are atomic(cannot be interrupted)
    • two process share two variables: int turn; boolean flag[2];
    • int turn = 0;
      boolean flag[2] = {false};
      
      while(true){
        flag[i] = true;
        turn = j;
        while(flag[j] && turn == j);  
      //critical section
      flag[i] = false; }

       

    • Proof: multual exclusion: assume both Pi and Pj are in there CS. then flag[j] = flag[i] = true; the test for entry can not be true for both processes at the same time, therefore one process must jave enyered its CS first. P1 cound not have found turn = 1 and therefore cound not have entered its CS.
            •   progress:  Case I: (Stuck)

              P1 is not interested in entering its CS 
              - then flag[1] = false 
              - hence the while loop is false for P0 and it can go

                              Case II: (Deadlock)
                                             P1 is also blocked at the while loop 
                                              - impossible, because turn = 0 or 1 
                                              - hence the while loop is false for some process and it can go

            • waiting:         Case III: (Starvation)

                                            P1 is executing its CS repeatedly 
              - upon exiting its CS, P1 sets flag[1] = false 
              - hence the while loop is false for P0 and it can go (sufficient?)

              However, P1 may attempt to re-enter its CS before P0 has a chance to run. 
              - but to re-enter, P1 sets flag[1] to true and sets turn to 0 
              - hence the while loop is true for P1 and it waits 
              - the while loop is now false for P0 and it can go

  • 硬件 同步
    • 解决办法基于locking
    • Uniprocessors - could disable interrupts. 没有效率
    • atomic hardware structions
    • using lock:     
      do{
          获取lock
          cs
          释放lock
          rs
      }while(true)

       

    • test and set :返回目标状态,并将它置为true
      boolean Test_and_Set (boolean *target)
      {
           boolean rv = *target;
           *target = TRUE;
           return rv:
      }

       

    • 用test and set: 如果锁为false,进入CS,并打开锁,用完后关闭锁
      do {
            while (Test_and_Set(&lock)); /* do nothing */
            /* critical section */
            lock = false;
            /* remainder section */
      } while (true);

       

    • Compare and swap: 返回value,如果与expect不同并将它置为new value
      int Compare_and_Swap(int *value, int expected, int new value) {
             int temp = *value;
             if (*value == expected)
                 *value = new value;
             return temp;
      }

      用compare and swap:同理

      do {
         while (compare_and_swap(&lock, 0, 1) != 0); /* do nothing */
          /* critical section */
          lock = 0;
          /* remainder section */
      } while (true);

       

    • 用test and set写限制长度的互斥:将waiting的数组i置为true,key置为ture,如果都对,对lock使用testandset。进入CS。如果j(i的下一个)和i不等,且jwaiting为true,当j和它下一个相等,如果j = i lock就释放,否则waiting【j】=false; 进入RS
      do {
                waiting[i] = true;
                key = true;
                while (waiting[i] && key)
                    key = Test_and_Set(&lock);
                waiting[i] = false;
                /* critical section */
                j = (i + 1) % n;
                while ((j != i) && !waiting[j])
                j = (j + 1) % n;
                if (j == i)
                    lock = false;
                else
                    waiting[j] = false;
                /* remainder section */
      } while (true);

       

  • 软件 同步
    • mutex lock:acquire() release() 会造成busy waiting,也成为自旋锁
    • acquire() {
           while (!available); /* busy wait */
           available = false;;
      }
      release() {
           available = true;
      }

       

    • semaphore:不一定需要busy waiting
        • S: wait()/P() signal()/V()
        • wait (S) {
                 while (S <= 0); // busy wait
                 S--;
          }
          signal (S) {
                 S++;
          }

           

        • no busy waiting
        • typedef struct{
               int value;
               struct process *list;
          } semaphore;
          wait(semaphore *S) {
                S->value--;
                if (S->value < 0) {
                   add this process to S->list;
                   block();
                }
          }
          signal(semaphore *S) {
                S->value++;
                if (S->value <= 0) {
                    remove a process P from S->list;
                    wakeup(P);
                }
          }

           

  • Bounded-Buffer Problem
    •   P:    C时交换full和empty
      do {
      ...
      /* produce an item in next_produced */
      ...
      wait(empty);
      wait(mutex);
      ...
      /* add next produced to the buffer */
      ...
      signal(mutex);
      signal(full);
      } while (true);

       

  • Readers-Writers Problem
  • 用数据集的方式解决并行问题-reader writer lock
  • variation:no reader kept waiting unless writer has permission already to use shared object.
      • 作家准备好就写。
  • 共享的数据有三个:rw_mutex = 1 //当第一个/最后一个读者
        •  mutex = 1 //用于保证read_count互斥性
        • read_count = 0 //
        • writer:每次rw_mutex-1,写完后再+1
        • writer:
          do {
               wait(rw_mutex);
                 ...
                 /* writing is performed */
                 ...
                 signal(rw_mutex);
          } while (true);

          reader: mutex-1, read+1,如果read=1,rw_mutex-1,mutex+1。

          • 开始读
          • mutex-1,read-1,如果read=0,就rw_mutex+1. mutex+1.
        • do {
                 wait(mutex);
                 read count++;
                 if (read count == 1)
                       wait(rw_mutex);
                 signal(mutex);
          .       ..
                 /* reading is performed */
                 wait(mutex);
                 read count--;
                 if (read_count == 0)
                       signal(rw_mutex);
                 signal(mutex);
          } while (true);

           

        • 即:作家写作前暂停读者,写完后释放。读者读书前先锁上mutex,排队,如果就剩1个读者了,rw-1,解开锁开始读书,读完后锁上mutex,read数-1,如果到0了,就rw+1,释放mutex。
  • 哲学家:数据集:饭;筷子(每人一个)
      • 等待筷子,等待右边的筷子,吃,放筷子,放右边的筷子;
      • do {
                wait ( chopstick[i] );
                wait ( chopStick[ (i + 1) % 5] );
                // eat
                signal ( chopstick[i] );
                signal (chopstick[ (i + 1) % 5] );
                // think
        } while (TRUE);

        这个算法会导致哲学家都吃不上饭——都在等右边的筷子,或者饿死

      • 用moniter:lock/zero or more条件(queue)//更抽象,内部只有一个进程执行
      • pickup()自己饿了,吃一个试试,如果失败了,就等等
      • 吃完后放筷子,思考
      • 试着吃时如果左右没在吃,就吃,并signal自己
      • 初始大家都在思考。

 

posted @ 2018-04-17 10:25  森淼clover  阅读(201)  评论(0)    收藏  举报