CS330 · Annotated SlidesChapter 6 — Process Synchronization
Chapter 6 · Annotated slides

Process Synchronization

Race conditions, the critical-section problem and its three requirements, Peterson’s solution, hardware support (test_and_set, swap), semaphores and their implementation, deadlock and starvation, the bounded-buffer, readers–writers and dining-philosophers problems, and monitors.

Slide text Study notes Highlight: key words Tips, tricks & traps Seen again elsewhere How it can come up
Slide 1: Slide 1
Exam weight Low

    Outline of this lecture

    In this lecture, we will discuss the following:

    • Background
    • The Critical-Section Problem
    • Solutions to the Critical-Section Problem
    • Classical Problems of Synchronization
    2
    Exam weight Low

      Objectives

      • To introduce the critical-section problem, whose solutions can be used to ensure the consistency of shared data
      • To present both software and hardware solutions of the critical-section problem
      • To examine several classical process-synchronization problems
      • To explore several tools that are used to solve process synchronization problems
      3
      Exam weight Low
        Slide 4: Background
        Exam weight Low
          Slide 5: Producer
          Exam weight Low
            Slide 6: Race condition example
            Exam weight Low
            1. count++ is load–increment–store; interleaving these steps from two processes can lose an update.
            Slide 7: Race Condition
            Exam weight High
            1. Race condition: the result depends on the order in which processes access shared data.
            🎯 How this can come up · 1 question
            MCQ

            A situation where the outcome depends on the order of access to shared data is a:

            Race condition

            • Shared-memory solution to bounded-buffer problem (see lecture 4) has a race condition on the class data count.
            • A situation where several processes access and manipulate the same data concurrently, and the outcome of the execution depends on the particular order in which access takes place.
            • Two or more processes reading and writing some shared data and final result depends on who runs precisely when.
            • To prevent race conditions, concurrent processes must be synchronized
            8
            Exam weight Low

              The Critical Section (CS) Problem

              • CS is the part of process code that manipulates shared data or resources.
              • Execution of the CS should be mutually exclusive - If a process is in its CS, then no other process can be in the same CS.
              • Each process must request permission to enter the CS in entry section, may follow critical section with exit section, then remainder section.
              • The Critical section problem is to design a protocol that the processes can use to cooperate.
              9
              Exam weight Low
                Slide 10: Critical Section
                Exam weight Low
                1. Critical section: the code that touches shared data. Structure: entry section, critical section, exit section, remainder section.

                Solution to Critical-Section Problem

                Solution to the Critical Section Problem must meet three

                conditions...

                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 sections, then only those processes that are not executing in their RS can participate in the decision on which will enter its CS next, & this selection cannot be postponed indefinitely.

                1. 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. This bound prevents Starvation
                11
                Exam weight High
                1. Requirements: Mutual exclusion (one at a time), Progress (no needless waiting when the CS is free), Bounded waiting (no starvation).
                Memory trickM-P-B: Mutual exclusion, Progress, Bounded waiting.
                🎯 How this can come up · 1 question
                MCQ

                Which is NOT a requirement of a critical-section solution?

                Types of Solutions

                • Software solutions
                  • algorithms who ’ s correctness does not rely on any other assumptions (OS or hardware)
                • Hardware solutions
                  • rely on special machine instructions
                • Operating System solutions
                  • provide special functions and data structures to the programmer
                12
                Exam weight Low

                  Peterson ’ s Solution

                  • Good algorithmic description of solving the 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
                  • The flag array is used to indicate if a process is ready to enter the critical section. flag[i] = true implies that process is P i ready!
                  13
                  Exam weight High
                  1. Peterson’s solution (2 processes): shared turn and flag[2]. Pᵢ sets flag[i] = true, turn = j, then waits while flag[j] && turn == j.

                  Algorithm for Process P

                  i

                  do {

                  flag[i] = true //process Pi is ready to enter its CS

                  ;

                  turn = j; //process Pj is allowed to execute in its CS while (flag[j] && turn == j);

                  critical section

                  flag[i] = false;

                  remainder section

                  } while (true);

                  Provable that

                  1.

                  Mutual exclusion is preserved (

                  the value of turn can be either i or j but cannot be both)

                  2.

                  Progress requirement is satisfied (A process cannot immediately re-enter the critical section if the other process has set its flag to true)

                  3.

                  Bounded-waiting requirement is met (a process will not wait longer than one turn

                  14
                  Exam weight Low

                    Drawbacks of Software Solutions

                    • Complicated to program
                    • Processes that are requesting to enter in their critical section are busy waiting (consuming processor time needlessly)
                    • If CS are long, it would be more efficient to block processes that are waiting (just as if they had requested I/O).
                    15
                    Exam weight Low

                      Synchronization Hardware

                      • Many systems provide hardware support for critical section code
                      • All solutions below based on idea of locking
                        • Protecting critical regions via locks
                        • Design of locks can be sophisticated
                      • Uniprocessors – could disable interrupts
                        • Currently running code would execute without preemption
                        • Generally too inefficient on multiprocessor systems (must tell all CPUs)
                          • Operating systems using this not broadly scalable
                      • Modern machines provide special atomic hardware instructions: Atomic = non-interruptable
                        • Two types:
                          • test memory word and set value
                          • swap contents of two memory words
                      16
                      Exam weight Low
                      1. Hardware support: atomic (uninterruptible) instructions such as test_and_set and compare_and_swap.

                      test_and_set Instruction

                      Definition:

                      boolean test_and_set (boolean *target) { boolean rv = *target; *target = TRUE; return rv: }

                      Executed atomically

                      1.

                      2.

                      Returns the original value of passed parameter

                      3.

                      Set the new value of passed parameter to “ TRUE ”

                      .

                      17
                      Exam weight Low
                      1. test_and_set returns the old value and sets the lock to true, in one atomic step.

                      Solution using test_and_set

                      • Shared boolean variable lock, initialized to FALSE
                      • Solution: do { while (test_and_set(&lock))

                      ; /* do nothing */ /* critical section */ lock = false; /* remainder section */ } while (true);

                      18
                      Exam weight Low

                        swap Instruction

                        • Definition: void Swap (boolean *a, boolean *b)

                        { boolean temp = *a; *a = *b; *b = temp:

                        }

                        19
                        Exam weight Low

                          Solution using swap

                          • Shared Boolean variable lock initialized to FALSE; Each process has a local Boolean variable key
                          • Solution: do { key = TRUE; while (key == TRUE)

                          Swap (&lock, &key ); // critical section lock = FALSE; // remainder section } while (TRUE);

                          20
                          Exam weight Low

                            Semaphore

                            • Synchronization tool that does not require busy waiting.
                            • Semaphore S – integer variable
                            • can only be accessed via two indivisible (atomic) operations
                            • Two standard operations modify S: wait and signal
                              • Originally called and V P
                            • Less complicated wait (S) { while (S <= 0) ; // busy wait S--; } signal (S) { S++; }
                            21
                            Exam weight High
                            1. Semaphore S: integer accessed only by wait() (P: decrement, block if < 0) and signal() (V: increment, wake one).
                            🎯 How this can come up · 1 question
                            MCQ

                            wait(S) on a semaphore:

                            Slide 22: Semaphore Usage
                            Exam weight High
                            1. Binary semaphore (0/1) = mutex lock. Counting semaphore controls access to N instances; initialize it to N.
                            🎯 How this can come up · 1 question
                            MCQ

                            A counting semaphore guarding 5 identical printers should be initialized to:

                            Semaphore Implementation

                            • Must guarantee that no two processes can execute wait and signal on the same semaphore at the same time
                            • Thus, implementation becomes the critical section problem where the wait and signal code are placed in the critical section
                              • Could now have busy waiting in critical section implementation
                                • But implementation code is short
                                • Little busy waiting if critical section rarely occupied
                            • Note that applications may spend lots of time in critical sections and therefore this is not a good solution
                            23
                            Exam weight Low
                            1. Busy waiting (spinlock) wastes CPU; better implementation blocks the process on the semaphore’s waiting list.

                            Semaphore Implementation with no Busy waiting

                            • With each semaphore there is an associated waiting queue
                            • Each entry in a waiting queue has two data items:
                              • value (of type integer)
                              • pointer to next record in the list
                            • Two operations:
                              • block – place the process invoking the operation on the appropriate waiting queue
                              • wakeup – remove one of processes in the waiting queue and place it in the ready queue
                            24
                            Exam weight Low

                              Semaphore Implementation with no Busy waiting (Cont.)

                              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); }

                              25
                              Exam weight Low

                                Deadlock and Starvation

                                • Deadlock – two or more processes are waiting indefinitely for an event that can be caused by only one of the waiting processes
                                • Let and be two semaphores initialized to 1 S Q P P 0 1 wait (S); wait (Q); wait (Q); wait (S); . . . . signal (S); signal (Q); signal (Q); signal (S);
                                • Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended.
                                • When P0 executes Wait(Q), it must wait until P1 executes Signal (Q) and when P1 executes Wait(S) ), it must wait until P0 executes Signal(S) .
                                26
                                Exam weight High
                                1. Deadlock: each process waits for an event only another waiting process can cause. Starvation: indefinite blocking.
                                🎯 How this can come up · 1 question
                                Written

                                P0 runs wait(S); wait(Q); and P1 runs wait(Q); wait(S); with S = Q = 1. What can happen?

                                Classical Problems of Synchronization

                                • Bounded-Buffer Problem
                                • Readers and Writers Problem
                                • Dining-Philosophers Problem
                                27
                                Exam weight Low

                                  Bounded-Buffer Problem

                                  • n buffers, each can hold one item
                                  • Semaphore mutex initialized to the value 1
                                  • Semaphore full initialized to the value 0
                                  • Semaphore empty initialized to the value n BUFFER
                                  28
                                  Exam weight High
                                  1. Bounded buffer: mutex = 1, full = 0, empty = n. Producer: wait(empty); wait(mutex); … signal(mutex); signal(full).
                                  Exam trapSwapping the order to wait(mutex); wait(empty) can deadlock when the buffer is full.
                                  🎯 How this can come up · 1 question
                                  MCQ

                                  In the bounded-buffer solution with n slots, empty starts at:

                                  Bounded Buffer Problem (Cont.)

                                  • The structure of the producer process do {

                                  ...

                                  /* produce an item in next_produced */

                                  ...

                                  wait(empty); //

                                  synchronize the use of the bounded buffer

                                  wait(mutex); //

                                  protect the CS for a shared value

                                  ...

                                  /* add next produced to the buffer */

                                  ...

                                  signal(mutex); signal(full); } while (true);

                                  29
                                  Exam weight Low

                                    Bounded Buffer Problem (Cont.)

                                     The structure of the consumer process do { wait(full); wait(mutex); ...

                                    /* remove an item from buffer to next_consumed */

                                    ...

                                    signal(mutex); signal(empty); ...

                                    /* consume the item in next consumed */

                                    ...

                                    30
                                    Exam weight Low
                                      Slide 31: Readers-Writers Problem
                                      Exam weight Low
                                      1. Readers–writers: many readers may read together; a writer needs exclusive access. rw_mutex = 1, mutex = 1, read_count = 0.
                                      Slide 32: Readers-Writers Problem (Cont.)
                                      Exam weight Low

                                        Readers-Writers Problem (Cont.)

                                        • The structure of a reader process do { wait(mutex); // Mutex protects READCOUNT from all the READERS read count++; if (read count == 1) // 1 st reader captures rw mutex for all readers wait(rw mutex); signal(mutex);

                                        ...

                                        /* reading is performed */

                                        ... wait(mutex);

                                        read count--; if (read count == 0)

                                        signal(rw mutex); signal(mutex); } while (true);

                                        33
                                        Exam weight Low
                                          Slide 34: Dining-Philosophers Problem
                                          Exam weight Low

                                            Dining-Philosophers Problem (Cont.)

                                            • Each philosopher is a process
                                            • One semaphore per chopstick:
                                              • chopstick: array[0..4] of semaphores initialized to 1 do { wait (chopstick[i] ); wait (chopStick[ (i + 1) % 5] ); // eat signal (chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // think } while (TRUE);
                                            • Deadlock if each philosopher start by picking his left chopstick
                                            35
                                            Exam weight High
                                            1. Dining philosophers: one semaphore per chopstick can deadlock if all pick up the left one at once.
                                            🎯 How this can come up · 1 question
                                            MCQ

                                            Which avoids deadlock in dining philosophers?

                                            Problems with Semaphores

                                            • semaphores provide a powerful tool for enforcing mutual exclusion and coordinate processes
                                            • But wait(S) and signal(S) are scattered among several processes. Hence, difficult to understand their effects
                                            • Usage must be correct in all the processes
                                            • Incorrect use of semaphore operations:
                                              • signal (mutex) ... . wait (mutex)
                                              • wait (mutex) ... wait (mutex)
                                              • Omitting of wait (mutex) or signal (mutex) (or both)
                                            • Deadlock and starvation
                                            36
                                            Exam weight Low
                                            1. Semaphore misuse: signal before wait, wait twice, or forgetting one → broken mutual exclusion or deadlock.

                                            Operating System Solutions: Monitors

                                            • Are high-level language constructs that provide equivalent functionality to that of semaphores but are easier to control.
                                            • But not powerful enough to model some synchronization schemes monitor monitor-name { // shared variable declarations procedure P1 (... ) { ... . } ... Procedure defined within the monitor procedure Pn (... ) { ...... } can access only those variables declared locally within the monitor Initialization code (... .) { ... } ... } } Syntax of a monitor
                                            37
                                            Exam weight Low
                                            1. Monitor: high-level construct; only one process active inside at a time.

                                            Operating System Solutions: Monitors

                                            • Is a software module containing:
                                              • one or more procedures
                                              • an initialization sequence
                                              • local data variables
                                            • Characteristics:
                                              • local variables accessible only by monitor ’ s procedures
                                              • a process enters the monitor by invoking one of its procedures
                                              • only one process can be in the monitor at any given time
                                            38
                                            Exam weight Low
                                              Slide 39: Operating System Solutions: Monitors
                                              Exam weight Low

                                                Variables

                                                Condition

                                                • The monitor construct is not sufficiently powerful for modeling some synchronization schemes-→ need to define additional mechanisms.
                                                • These mechanisms are provided by the condition construct.
                                                • A programmer who needs to write a tailor-made synchronization scheme can define one or more variable of type condition:
                                                • condition x, y;
                                                • Two operations on a condition variable:
                                                  • x.wait – a process that invokes the operation is suspended.
                                                  • x.signal – resumes one suspended processes (if any) that invoked x.wait
                                                    • If no x.wait on the variable, then it has no effect on the variable
                                                40
                                                Exam weight Low
                                                1. Condition variables: x.wait() suspends the caller; x.signal() resumes one waiting process (no effect if none).
                                                Slide 41: Monitor with Condition Variables
                                                Exam weight Low

                                                  Condition Variables choices

                                                  • If process P invokes x.signal, with Q in x.wait state, what should happen next?
                                                    • If Q is resumed, then P (signaling process) must wait
                                                  • Options include
                                                    • Signal and wait
                                                      • P waits until Q leaves monitor or waits for another condition
                                                    • Signal and continue – Q waits until P leaves the monitor or waits for another condition
                                                    • Both have pros and cons – language implementer can decide
                                                    • Implemented in other languages including Mesa, C#, Java
                                                  42
                                                  Exam weight Low
                                                    Slide 43: Solution to Dining Philosophers
                                                    Exam weight Low

                                                      Solution to Dining Philosophers (cont)

                                                      void test (int i) { if ((state[(i + 4) % 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) % 5] != EATING) ) { state[i] = EATING;

                                                      self[i].signal;

                                                      } }

                                                      initialization_code {

                                                      for (int i = 0; i < 5; i++) state[i] = THINKING; }

                                                      }

                                                      44
                                                      Exam weight Low

                                                        Process Synchronization Conclusion

                                                        • A variety of methods exist, and each method has different variations.
                                                        • The most commonly used are semaphores and monitors.
                                                        • Monitors are the easiest to use, closest to programmer ’ s needs.
                                                        • The simpler mechanisms can be used to implement more sophisticated ones.
                                                        • No mechanism prevents in principle deadlocks, starvation, or busy waiting but more sophisticated mechanisms make it easier to avoid them.
                                                        45
                                                        Exam weight Low