synchronization

Document Sample
synchronization Powered By Docstoc
					Chapter 6 Synchronization

       Dr. Yingwu Zhu
     The Problem with Concurrent
              Execution
• Concurrent processes (& threads) often access
  shared data and resources
  – Need controlled access to the shared data;
    otherwise result in an inconsistent view of this
    data
• Maintaining data consistency must ensure
  orderly execution of cooperating processes
              Simple Example
• Threads T1 and T2      Shared variables in, out;
  are executing the
  same procedure         Procedure Echo();
  using the same            read (in, keyboard);
  variables in and out      out := in;
• Threads can be             write (out, screen);
  interrupted            end Echo;
  anywhere
• What can happen?
              Simple Example
• Threads T1 and T2      Shared variables in, out;
  are executing the
  same procedure         Procedure Echo();
  using the same            read (in, keyboard);
  variables in and out      out := in;
• Threads can be             write (out, screen);
  interrupted            end Echo;
  anywhere
• What can happen?
Race Condition & Critical-Section Problem

  • Race condition
     – Multiple processes manipulate same data
       concurrently
     – The outcome of execution depends on the
       particular order in which the data access takes
       place
  • Critical Section
     – Multiple processes has a segment of code, called
       critical section which handle race condition
     – Admission to the critical section MUST be
       coordinated
       Race Condition: Example
• count++ could be implemented as
     register1 = count
     register1 = register1 + 1
     count = register1
• count-- could be implemented as
     register2 = count
     register2 = register2 - 1
     count = register2
• Consider this execution interleaving with “count = 5” initially:
      S0: producer execute register1 = count {register1 = 5}
      S1: producer execute register1 = register1 + 1 {register1 = 6}
      S2: consumer execute register2 = count {register2 = 5}
      S3: consumer execute register2 = register2 - 1 {register2 = 4}
      S4: producer execute count = register1 {count = 6 }
      S5: consumer execute count = register2 {count = 4}
      Critical-Section Problem
Each process looks like:
   do {
                      Entry Section


                CRITICAL SECTION

                      Exit Section

                REMAINDER SECTION

    } while (TRUE);
Solution to Critical-Section Problem
MUST satisfy the following three requirements:
1. Mutual Exclusion - If process Pi is executing in its critical section,
   then no other processes can be executing in their critical sections
2. Progress - If no process is executing in its critical section and there
   exist some processes that wish to enter their critical section, then
   the selection of the processes that will enter the critical section next
   cannot be postponed indefinitely
3. Bounded Waiting - A bound must exist on the number of times
   that other processes are allowed to enter their critical sections after
   a process has made a request to enter its critical section and before
   that request is granted
       Assume that each process executes at a nonzero speed
       No assumption concerning relative speed of the N processes
            Types of Solutions
• Software solutions
  – Algorithms whose correctness does not depend on
    any assumptions other than positive processing speed
    (NO failures!)
  – Busy waiting
• Hardware solutions
  – Rely on some special machine instructions
• OS solutions
  – Extending hardware solutions to provide some
    functions and data structure support to the
    programmer
   Software Solution (incomplete)
• Only 2 processes      Shared flag: array[0..1] of
                          boolean = [false, false];
• Local process is i,
  the other is j        Repeat
• What is good?            flag[i] := true;
                          while flag[j] do no-op;
• What is bad?
                            critical section;
                           flag[i] := false;
                            remainder section;
                        Forever
   Software Solution (incomplete)
• Only 2 processes           Shared flag: array[0..1] of
• Local process is i, the      boolean = [false, false];
  other is j
• Mutual exclusion – good    Repeat
• Progress – bad, if both       flag[i] := true;
  executed the 2nd line        while flag[j] do no-op;
• Bounded time – irrelvant       critical section;
                                flag[i] := false;
                                 remainder section;
                             Forever
    Software Solution (Peterson’s)
• Only 2 processes          Shared turn: (0..1) = 0;
• Local process is i, the   Shared flag: array[0..1] of
                               boolean = [false, false];
  other is j
• Mutual exclusion – good
                            Repeat
• Progress – good              flag[i] := true; turn := j;
• Bounded time – good         while (flag[j] && turn = j)
                                   do no-op;
                                critical section;
                               flag[i] := false;
                                remainder section;
                            Forever
             Peterson’s Solution
• A classic software-based solution to the critical-section
  problem
• Two process solution
• Assume that the LOAD and STORE instructions are
  atomic; that is, cannot be interrupted.
• The two processes share two variables:
   – int turn;
   – Boolean flag[2]
• The variable turn indicates whose turn it is to enter the
  critical section. If turn == i, then process Pi is allowed
  to execute in its critical section
• The flag array is used to indicate if a process is ready to
  enter the critical section. flag[i] = true implies that
  process Pi is ready!
Hardware Solution – Disable Interrupts
• Correct solution for uni-
  processor machine
                               Repeat
   – Atomic instructions
• During critical section,        disable interrupts;
  multiprogramming is not          critical section;
  utilized  perf. penalty        enable interrupts;
• Too inefficient for multi-       remainder section;
  processor machines,
  interrupt disabling          Forever
  message passing to all
  processors, delay entrance
  to critical section
   Hardware Solution – Test and Set
• Test and modify the         Shared boolean lock:= false;
  content of a word           Repeat
  atomically                  while ( TestAndSet (&lock ));
                                  critical section
boolean TestAndSet (boolean        lock = FALSE;
   *target)                         remainder section
{                             Forever
      boolean rv = *target;
      *target = TRUE;
      return rv:
 }
           OS Solution - Semaphores
• Synchronization tool that does
  not require busy waiting         semaphore S; // initialized to 1
                                   wait (S);
• 2 atomic operations that
                                       Critical Section
  logically look like this:
                                    signal (S);
   S: integer
   wait (S) {
         while S <= 0; // no-op
         S--;
       }

    signal (S) {
        S++;
      }
       Semaphore Implementation

• With each semaphore there is an associated waiting
  queue. Each semaphore has two data items:
     typedef struct {
         int value;
         struct PCB *list;
     } semaphore;

• Two operations:
   – Block : place the process invoking the operation on the
     waiting queue.
   – Wakeup: remove one of processes in the waiting queue and
     place it in the ready queue.
             Semaphore Implementation
• Implementation of wait:
         wait (S){
               value--;
               if (value < 0) {
                          add this process P to waiting queue
                          block(P);
             }
         }

• Implementation of signal:
         Signal (S){
                 value++;
                  if (value <= 0) {
                             remove a process P from the waiting queue
                             wakeup(P);
               }
         }
          Semaphore Properties
• S.value >= 0: value is the # of additional process
  that can execute wait(s) w/o blocking
• S.value < 0: abs(value) is the # of processes
  blocked on the waiting queue
• Atomicity:
   – No two processes in wait() and signal() at the same
     time
   – No even one in wait() and one in signal(), even with
     multiple CPUs
   – Uniprocessor: disable interrupts
   – Multiprocessor: software or hardware scheme
                 Semaphore Types
• Counting semaphore – integer value can range over
  an unrestricted domain
   – Used to control access to a given resource consisting of a finite
     number of instances
   – The semaphore is initialized to the number of resources available
• Binary semaphore – integer value can range only
  between 0 and 1; can be simpler to implement
   – Also known as mutex locks
     Producer-Consumer Problem
• Also called the bounded-buffer problem
• A producer produces data that is consumed by a
  consumer
• A buffer holds data that holds produced data that is
  not yet consumed!
• Multiple producers and consumers
• Initially we assume the buffer is unbounded

         0     1     2     3     4    ……



              out               in
       Producer-Consumer: unbounded
                   buffer
                         Initialization: semaphores: mutex = 1, full = 0;
                                          integers: int = 0, out = 0;
void append(int d) {
  buffer[in++] = d;      Producer:                       Consumer:
}
                         While (1) {                     While (1) {
                           produce x;                      wait(full);
                           wait(mutex);                    wait(mutex);
int take() {               append(x);                      x = take();
                           signal(mutex);                  signal(mutex);
  int x = buffer[out];
                           signal(full);                   consume x;
  out++;                 }                               }
  return x;
}
                         [1] Does it matter to switch two signal() in producer?
                         [2] Does it matter to switch two signal() in consumer?
 Producer-Consumer: Bounded Buffer
• As before, the consumer can take when the number of data
  items is >=1
• This time, the producer can append when the number of
  empty slots >=1
• Can you modify the previous code to accommodate a
  bounded buffer?
• Hint: the consumer produces empty slots!
• Cyclic buffer:


                 0     1     2      3      4



                      out                 in
   Producer-Consumer: bounded buffer
                       Initialization: semaphores: mutex = 1, full = 0; empty = N;
                                        integers: int = 0, out = 0;
void append(int d) {
  buffer[in] = d;      Producer:                      Consumer:
  in = (in + 1) % N;
}                      While (1) {                    While (1) {
                         produce x;                      wait(full);
                         wait(empty);                    wait(mutex);
                         wait(mutex);                    x = take();
int take() {             append(x);                      signal(mutex);
  int x = out;           signal(mutex);                  signal(empty);
                         signal(full);                  consume x;
  out = (ouit+1) %N;
                       }                              }
  return buffer[x];
}
      Readers-Writers Problem
• A data set is shared among a number of concurrent
  processes
   – Readers – only read the data set; they do not perform any updates
   – Writers – can both read and write.

• Problem – allow multiple readers to read at the same
  time. Only one single writer can access the shared data at
  the same time (if on writer access it, no readers or other
  writers are allowed to access the data).
• Shared Data
   – Data set
• Using semaphores
   – What semaphores do we need?
     Readers-Writers Problem
– Semaphore mutex initialized to 1.
– Semaphore wrt initialized to 1.
– Integer readcount initialized to 0.
Readers-Writers Problem (Cont.)

• Exercise: Implement readers and writers
           Readers-Writers Problem
                Initialization: semaphores: mutex = 1, wrt = 1;
                                 integers: readcount = 0;

Reader:
                                                Writer:
wait(mutex);
readcount++;                                        wait(wrt);
If (readcount==1)                                   write;
   wait(wrt);
                                                    signal(wrt);
signal(mutex);
read;                                           }
wait(mutex);
readcount--;
If(readcount==0)
   signal(wrt);
signal(mutex);

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:4
posted:9/9/2011
language:English
pages:28