Title: Chapter 6: Process Synchronization
1Chapter 6 Process Synchronization
2Chapter 6 Process Synchronization
- Background
- The Critical-Section Problem
- Petersons Solution
- Synchronization Hardware
- Semaphores
- Classic Problems of Synchronization
- Monitors
- Synchronization Examples
- Atomic Transactions
3Background
- Q Why is synchronization an issue?
- A Concurrent access to shared data may result in
data inconsistency. - Goal Maintain data consistency
- Approach develop mechanisms to ensure orderly
execution of cooperating processes.
4Background
- Recall the shared-memory solution to
bounded-buffer problem (Chapter 3) - Soln. allows at most N 1 items in buffer at the
same time. - Q how can we use all N buffers?
- A solution, where all N buffers are used is not
simple. - Suppose that we modify the producer-consumer code
by adding a variable counter, initialized to 0
and incremented each time a new item is added to
the buffer
5Bounded-Buffer
- Shared data
- define BUFFER_SIZE 10
- typedef struct
- . . .
- item
- item bufferBUFFER_SIZE
- int in 0
- int out 0
- int counter 0
6Producer
- while (true)
-
- / produce an item
and put in nextProduced - while (counter BUFFER_SIZE)
- // do nothing
- buffer in nextProduced
- in (in 1) BUFFER_SIZE
- counter
-
7Consumer
- while (1)
-
- while (counter 0)
- // do nothing
- nextConsumed bufferout
- out (out 1) BUFFER_SIZE
- counter--
- / consume the item in nextConsumed
-
8Bounded Buffer
- The statementscountercounter--must be
performed atomically. - Atomic operation means an operation that
completes in its entirety without interruption. - Lets see what happens if they are not performed
atomically
9Race Condition
- counter could be implemented as register1
counter register1 register1 1
counter register1 - counter- - could be implemented as
register2 counter register2 register2 -
1 counter register2
10Race Condition
- If both the producer and consumer attempt to
update the buffer concurrently, the assembly
language statements may get interleaved. - Interleaving depends upon how the producer and
consumer processes are scheduled. - How is this possible?
11Race Condition
- Consider this execution interleaving with
counter 5 initially - S0 producer execute register1 counter
register1 5S1 producer execute register1
register1 1 register1 6 S2 consumer
execute register2 counter register2 5
S3 consumer execute register2 register2 - 1
register2 4 S4 consumer execute counter
register2 counter 4 - S5 producer execute counter register1
counter 6 - Consider another execution interleaving with
counter 5 initially - S0 producer execute register1 counter
register1 5S1 producer execute register1
register1 1 register1 6 S2 consumer
execute register2 counter register2 5
S3 consumer execute register2 register2 - 1
register2 4 S4 producer execute counter
register1 counter 6 S5 consumer execute
counter register2 counter 4
12Race Condition
- Race condition The situation where several
processes access and manipulate shared data
concurrently. The final value of the shared data
depends upon which process finishes last. - Why do you think it is called a race condition?
- The final value of the shared data depends upon
which process finishes last. Some race -) - To prevent race conditions, concurrent processes
must be synchronized. - What does synchronization do?
- It forces a specific ordering of events.
13The Critical-Section Problem
- Definition
- n processes all competing to use some shared data
- Each process has a code segment, called critical
section, in which the shared data is accessed. - Problem ensure that when one process is
executing in its critical section, no other
process is allowed to execute in its critical
section.
14Solution to Critical-Section Problem
- 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
15Petersons Solution
- 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 flag2
- 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. flagi
true implies that process Pi is ready!
16Algorithm for Process Pi
- do
- flagi TRUE
- turn j
- while (flagj turn j)
- CRITICAL SECTION
- flagi FALSE
- REMAINDER SECTION
- while (TRUE)
- Why does this not generalize to more than two
processes?
17Synchronization Hardware
- Many systems provide hardware support for
critical section code - Uniprocessors could disable interrupts
- Currently running code would execute without
preemption - Generally too inefficient on multiprocessor
systems - Operating systems using this not broadly scalable
- Modern machines provide special atomic hardware
instructions - Atomic non-interruptable
- Either test memory word and set value
- Or swap contents of two memory words
18TestAndSet Instruction
- Definition
- boolean TestAndSet (boolean target)
-
- boolean rv target
- target TRUE
- return rv
-
19Solution using TestAndSet
- Shared boolean variable lock, initialized to
false. - Solution
- do
- while (TestAndSet (lock))
- / do nothing
- // critical section
- lock FALSE
- // remainder section
- while (TRUE)
-
20Swap Instruction
- Definition
- void Swap (boolean a, boolean b)
-
- boolean temp a
- a b
- b temp
-
21Solution 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)
-
22Semaphore
- Synchronization tool that does not require busy
waiting - Semaphore S integer variable
- Two standard operations modify S wait() and
signal() - Originally called P() and V()
- Less complicated
- Can only be accessed via two indivisible (atomic)
operations - Note below are possible semantics but NOT
implementation - wait (S)
- while S lt 0
- // no-op
- S--
-
- signal (S)
- S
-
23Semaphore as General Synchronization Tool
- Counting semaphore integer value can range over
an unrestricted domain - Binary semaphore integer value can range only
between 0 and 1 can be simpler to implement - Also known as mutex locks
- Can implement a counting semaphore S as a binary
semaphore - Provides mutual exclusion
- Semaphore S // initialized to 1
- wait (S)
- Critical Section
- signal (S)
24Semaphore 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. Huh??? Do we understand
this point? - 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. -
25Semaphore 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. -
26Semaphore Implementation with no Busy waiting
(Cont.)
- Implementation of wait
- wait (S)
- value--
- if (value lt 0)
- add this process to waiting
queue - block()
-
- Implementation of signal
- signal (S)
- value
- if (value lt 0)
- remove a process P from the
waiting queue - wakeup(P)
-
27Deadlock 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 S and Q be two semaphores initialized to 1
- P0 P1
- 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.
28Classical Problems of Synchronization
- Bounded-Buffer Problem
- Readers and Writers Problem
- Dining-Philosophers Problem
29Bounded-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.
30Bounded Buffer Problem (Cont.)
- The structure of the producer process
- do
- // produce an item
- wait (empty)
- wait (mutex)
- // add the item to the
buffer - signal (mutex)
- signal (full)
- while (true)
31Bounded Buffer Problem (Cont.)
- The structure of the consumer process
- do
- wait (full)
- wait (mutex)
- // remove an item from
buffer - signal (mutex)
- signal (empty)
-
- // consume the removed item
- while (true)
32Readers-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. - Shared data
- Data set
- Semaphore mutex initialized to 1.
- Semaphore wrt initialized to 1.
- Integer readcount initialized to 0.
33Readers-Writers Problem (Cont.)
- The structure of a writer process
-
- do
- wait (wrt)
-
- // writing is performed
- signal (wrt)
- while (true)
-
34Readers-Writers Problem (Cont.)
- The structure of a reader process
-
- do
- wait (mutex)
- readcount
- if (readcount 1) wait
(wrt) - signal (mutex)
-
- // reading is
performed - wait (mutex)
- readcount - -
- if (readcount 0) signal
(wrt) - signal (mutex)
- while (true)
-
35Dining-Philosophers Problem
- Shared data
- Bowl of rice (data set)
- Semaphore chopstick 5 initialized to 1
36Dining-Philosophers Problem (Cont.)
- The structure of Philosopher i
- do
- wait ( chopsticki )
- wait ( chopstick (i 1) 5 )
-
- // eat
- signal ( chopsticki )
- signal ( chopstick (i 1) 5 )
-
- // think
- while (true)
37Dining-Philosophers Problem (Cont.)
- Do you see any problem with this solution?
- Deadlock may occur
- All five philosophers become hungry
simultaneously and each grabs her left chopstick
when each philosopher tries to grab her right
chopstick she will be delayed forever - Possible solutions
- Allow at most four philosophers
- Allow a philosopher to pick up chopsticks only if
both chopsticks are available (done in a critical
section) - Asymmetric solution odd philosopher picks up
left chopstick first, even philosopher picks up
right chopstick first
38Problems with Semaphores
- Incorrect use of semaphore operations
- signal (mutex) . wait (mutex)
- wait (mutex) wait (mutex)
- Omitting of wait (mutex) or signal (mutex) (or
both)
39Monitors
- A high-level abstraction that provides a
convenient and effective mechanism for process
synchronization - Only one process may be active within the monitor
at a time - monitor monitor-name
-
- // shared variable declarations
- procedure P1 () .
-
- procedure Pn ()
- initialization code ()
-
40Schematic view of a Monitor
41Condition Variables
- To allow a process to wait within the monitor, a
condition variable must be declared, as - condition x, y
- Two operations on a condition variable
- x.wait () a process that invokes the operation
is - suspended.
- x.signal () resumes one of processes (if any)
that - invoked x.wait ()
42 Monitor with Condition Variables
43Solution to Dining Philosophers
- monitor dp
-
- enum THINKING, HUNGRY, EATING state 5
- condition self 5
- void pickup (int i)
- statei HUNGRY
- test(i)
- if (statei ! EATING) self i.wait()
-
-
- void putdown (int i)
- statei THINKING
- // test left and right
neighbors - test((i 4) 5)
- test((i 1) 5)
-
-
44Solution to Dining Philosophers (cont)
- void test (int i)
- if ( (state(i 4) 5 ! EATING)
- (statei HUNGRY)
- (state(i 1) 5 ! EATING) )
- statei EATING
- selfi.signal ()
-
-
- initialization_code()
- for (int i 0 i lt 5 i)
- statei THINKING
-
45Monitor Implementation Using Semaphores
- Variables
- semaphore mutex // (initially 1)
- semaphore next // (initially 0)
- int next_count 0
- Each external procedure F will be replaced by
- wait(mutex)
-
- body of F
-
- if (next_count gt 0)
- signal(next)
- else
- signal(mutex)
- Why is this done?
- Mutual exclusion within a monitor is ensured.
46Monitor Implementation
- For each condition variable x, we have
- semaphore x_sem // (initially 0)
- int x_count 0
- The operation x.wait can be implemented as
-
- x_count
- if (next_count gt 0)
- signal(next)
- else
- signal(mutex)
- wait(x_sem)
- x_count--
-
47Monitor Implementation
- The operation x.signal can be implemented as
- if (x_count gt 0)
- next_count
- signal(x_sem)
- wait(next)
- next_count--
-
-
48Monitor Implementation
- When we wake a process in the monitor, which
process do we wake? - Conditional-wait construct x.wait(c)
- c integer expression evaluated when the wait
operation is executed. - value of c (a priority number) stored with the
name of the process that is suspended. - when x.signal is executed, process with smallest
associated priority number is resumed next. - Check two conditions to establish correctness of
system - User processes must always make their calls on
the monitor in a correct sequence. - Must ensure that an uncooperative process does
not ignore the mutual-exclusion gateway provided
by the monitor, and try to access the shared
resource directly, without using the access
protocols.
49Synchronization Examples
- Solaris
- Windows XP
- Linux
- Pthreads
50Solaris Synchronization
- Implements a variety of locks to support
multitasking, multithreading (including real-time
threads), and multiprocessing - Uses adaptive mutexes for efficiency when
protecting data from short code segments - spinlock in case of executing thread
- blocking semaphore in case of ready/waiting
thread - Uses condition variables and readers-writers
locks when longer sections of code need access to
data - Uses turnstiles to order the list of threads
waiting to acquire either an adaptive mutex or
reader-writer lock - What is a turnstile?
- A queue containing threads blocked on a lock
- Solaris allocates turnstiles to kernel threads
instead of objects. - The first thread gives its turnstile to the
object it wants to lock - The thread gains a new turnstile from a list of
free turnstiles.
51Windows XP Synchronization
- Uses interrupt masks to protect access to global
resources on uniprocessor systems - Uses spinlocks on multiprocessor systems
- Also provides dispatcher objects which may act as
either mutexes or semaphores - Dispatcher objects may also provide events
- An event acts much like a condition variable
52Linux Synchronization
- Linux
- disables interrupts to implement short critical
sections - Linux provides
- semaphores
- spinlocks
53Pthreads Synchronization
- Pthreads API is OS-independent
- It provides
- mutex locks
- condition variables
- Non-portable extensions include
- read-write locks
- spin locks
54End of Chapter 6