zoukankan      html  css  js  c++  java
  • [os] Pthread: Synchronization, Deadlock , Semaphore

    Synthronization

    • mutual exclusion:

    "dekker's algorithm": Dekker's algorithm is the first known correct solution to the mutual exclusion problem in concurrent programming.

     /* global or shared memory */
                        int x = 5;
                        int needLockT1 = 0;   /* 0 or 1 */
                        int needLockT2 = 0;   /* 0 or 1 */
                        int turn = T1;        /* T1 or T2 */
    
      /* Thread T1 */                      /* Thread T2 */
      while ( 1 )                              while ( 1 )
      {                                            {
        execNonCriticalSection();            execNonCriticalSection();
        needLockT1 = 1;                          needLockT2 = 1;
        turn = T2;                                       turn = T1;                 // compete for the 'turn'
    
        while ( turn == T2 &&                while ( turn == T1 &&
                needLockT2 == 1 )                    needLockT1 == 1 )
        {                                            {
          /* busy wait */                              /* busy wait */
        }                                            }
    
        execCriticalSection();               execCriticalSection();
        needLockT1 = 0;                      needLockT2 = 0;
      }                                                }
    
    
    T1: needLockT1 = 1;
    T1: turn = T2;
    T2: needLockT2 = 1;
    T2: turn = T1;
    T1: execCriticalSection();
    T1: needLockT1 = 0;
    T2: execCriticalSection();
    
    

    Semaphore:

    "a system of sending messages by holding the arms or two flags or poles in certain positions according to an alphabetic code."

    -- an OS construct that enables us to have synchronized access
    to one or more shared resources

    -- special non-negative int variable

    -- two operations:

    (1) first operation essentially attempts to gain access

       P()     proberen (to try)
       wait()
       down()
    

    (2) second operation relinquishes the access the acquired

       V()     vrijgeven (to release)
       signal()
       up()
    

    semaphore S is non-negative int variable

      P( semaphore S )                         /* this P() operation MUST execute without    */
      {                                                    /*  any interruption, i.e., no context switch */
        while ( S == 0 ) /* resource count*/          /*   between exiting the while() loop and     */
        {                                              /*    executing S--                           */
          /* busy wait */
        }
        S--;
      }
    
      V( semaphore S )
      {
        S++;
      }
    
    • the "producer/consumer" problem (a.k.a. shared buffer problem)

    -- Given a shared buffer (i.e., array) of a fixed size n
    -- One or more producer threads
    -- One or more consumer threads

                            /* shared/global memory */
                            int n = 20;
                            buffer[n];
                            semaphore empty_slots = n;
                            semaphore used_slots = 0;
                            semaphore mutex = 1;
    
      /* producer */                           /* consumer */
      while ( 1 )                              while ( 1 )
      {                                        {
        item = produce_next_item();              P( used_slots );
        P( empty_slots );                          P( mutex );
          P( mutex );                                item = remove_from_buffer();
            add_to_buffer( item );                 V( mutex );
          V( mutex );                            V( empty_slots );
        V( used_slots );                         consume( item );
      }                                        }
    
    

    uses two counting semaphores to ensure:
    (1) no buffer overflow will occur in a producer
    (2) no reading from an empty buffer in the consumer

    Uses mutex to ensure the add/remove could be exclusively happening at the same time.

    "A Mutex is different than a semaphore as it is a locking mechanism while a semaphore is a signalling mechanism. A binary semaphore can be used as a Mutex but a Mutex can never be used as a semaphore."

    • DINING PHILOSOPHERS PROBLEM

    Given: five philosophers that engage in only two activities:
    -- thinking (i.e., independent computation)
    -- eating (i.e., sharing a resource; therefore, requires synchronization)
    Given: shared table with five bowls and five chopsticks,
    and a bowl of food in the middle of the table
    (which is endlessly replenished)
    Key contraint: to eat(), a philosopher must obtain two chopsticks,
    one from the left, one from the right

    First attempt:

    chopstick is array[5] of semaphores

      philosopher( i )     /* i in 0..4 */
      {
        while ( 1 )
        {
          think()
          P( chopstick[i] )   //DEADLOCK
            P( chopstick[i+1%5] )
              eat()                 /* critical section */
            V( chopstick[i+1%5] )
          V( chopstick[i] )
        }
      }
    

    Second attempt:

    chopstick is array[5] of semaphores

      philosopher( i )     /* i in 0..4 */
      {
        while ( 1 )
        {
          think()
          P( mutex );  // top-level mutex -- NOT EFFICIENT
            P( chopstick[i] )
            P( chopstick[i+1%5] )
          V( mutex );
          eat()                 /* critical section */
          V( chopstick[i+1%5] )
          V( chopstick[i] )
        }
      }
    
    

    Third attempt:

    -- use an asymmetric solution

    chopstick is array[5] of semaphores

      philosopher( i )     /* i in 0..3 (instead of i in 0..4) */
      {
        while ( 1 )
        {
          think()
          P( chopstick[i] )
            P( chopstick[i+1%5] )
              eat()                 /* critical section */
            V( chopstick[i+1%5] )
          V( chopstick[i] )
        }
      }
    
      philosopher( i )     /* i is always 4 */    /*it holds the slots required as the "left" chopsticks for both its nbrs*/
      {
        while ( 1 )
        {
          think()
          P( chopstick[i+1%5] )    /* we swapped the order of the P() operations */
            P( chopstick[i] )
              eat()                 /* critical section */
            V( chopstick[i] )
          V( chopstick[i+1%5] )
        }
      }
    
    

    Deadlock

    Deadlock: We have deadlock when no process/thread can make any
    further progress (i.e., all blocked on P() operation
    and the given resource will NEVER become available)

    Deadlock requires four conditions:
    -- mutual exclusion
    -- hold and wait
    -- no preemption
    -- circular wait -- i.e., a cycle in resource allocation graph

    Deadlock:

    1. "classical circular"

    2. circular: P1, P2, R1, R2

  • 相关阅读:
    Effective C++ 读书笔记(3544):继承关系与面向对象设计
    《全景探秘游戏设计艺术》读后感之引子
    Effective C++ 读书笔记(1117):构造析构和赋值函数
    Effective C++ 读书笔记(2934):类与函数之实现
    Unity中使用PersistentDataPath加载文件
    打开本地【C】【D】【E】驱动器时候提示 X:\ 找不到应用程序
    C#进制转换
    在VS里编辑unity代码调用系统方法不显示中文注释或英文注释
    Spreadsheet说明
    C#中删除控件的事件的方法类.
  • 原文地址:https://www.cnblogs.com/manqing/p/10597445.html
Copyright © 2011-2022 走看看