05 Synchronization
05 Synchronization
SYSTEMS
OS 1
Lesson 6: PROCESS
SYNCHRONIZATION
Nguyễn Thị Hậu (UET-VNU)
nguyenhau@vnu.edu.vn
CONTENTS
• Background
• The Critical-Section Problem
• Peterson ‘s Solution
• Semaphores
OS 2
• Examples
Background
• Processes can execute concurrently
• May be interrupted at any time, partially completing
execution
• Concurrent access to shared data may result in data
inconsistency
OS
• Maintaining data consistency requires mechanisms to
ensure the orderly execution of cooperating processes
3
Race Condition
• Processes P0 and P1 are creating child processes using the
fork() system call
• Race condition on kernel variable next_available_pid
which represents the next available process identifier (pid)
OS
• Unless there is a mechanism to prevent P0 and P1 from
accessing the variable next_available_pid the same 4
pid could be assigned to two different processes!
Producer-Consumer
• Global shared data: counter, BUFFER[], BUFFER_SIZE
OS
5
OS
6
Critical Section Problem
• Consider system of n processes {p0, p1, … pn-1}
• Each process has critical section segment of code
• Process may be changing common variables, updating table, writing file,
etc.
• When one process in critical section, no other may be in its critical section
• Critical section problem is to design protocol to solve this
OS
• Each process must ask permission to enter critical section in entry
section, may follow critical section with exit section, then
remainder section
7
Critical Section
• General structure of process Pi
OS
8
Critical-Section Problem (Cont.)
Requirements for solution 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
OS
selection of the process 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 9
Interrupt-based Solution
• Entry section: disable interrupts
• Exit section: enable interrupts
• Will this solve the problem?
• What if the critical section is code that runs for an hour?
• Can some processes starve – never enter their critical section.
• What if there are two CPUs?
OS
10
Peterson’s Solution
• Two process solution
• Assume that the load and store machine-
language instructions are atomic; that is, cannot be
interrupted
• The two processes share two variables:
• int turn;
OS
• boolean flag[2]
flag[i] = true;
turn = j;
while (flag[j] && turn = = j)
OS
;
/* critical section */
flag[i] = false;
/* remainder section */
12
}
Correctness of Peterson’s Solution
• Provable that the three CS requirement are met:
1. Mutual exclusion is preserved
Pi enters CS only if:
either flag[j] = false or turn = i
2. Progress requirement is satisfied
OS
3. Bounded-waiting requirement is met
13
Peterson’s Solution and Modern
Architecture
• Although useful for demonstrating an algorithm,
Peterson’s Solution is not guaranteed to work on
modern architectures.
• To improve performance, processors and/or
compilers may reorder operations that have no
OS
dependencies
• Understanding why it will not work is useful for better
understanding race conditions.
• For single-threaded this is ok as the result will always
be the same.
• For multithreaded the reordering may produce
inconsistent or unexpected results! 14
Modern Architecture Example
• Two threads share the data:
boolean flag = false;
int x = 0;
• Thread 1 performs
while (!flag)
print x;
OS
• Thread 2 performs
x = 100;
flag = true;
• What is the expected output?
100
15
Modern Architecture Example
(Cont.)
• However, since the variables flag and x are independent of each
other, the instructions:
flag = true;
x = 100;
OS
for Thread 2 may be reordered
• If this occurs, the output may be 0!
16
Peterson’s Solution Revisited
• The effects of instruction reordering in Peterson’s Solution
OS
• This allows both processes to be in their critical section at the
same time!
• To ensure that Peterson’s solution will work correctly on
modern computer architecture we must use Memory Barrier.
17
Synchronization Hardware
• Many systems provide hardware support for implementing
the 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
OS
• We will look at three forms of hardware support:
1. Hardware instructions
2. Atomic variables
18
Hardware Instructions
• Special hardware instructions that allow us to
either test-and-modify the content of a word, or to
swap the contents of two words atomically
(uninterruptedly.)
• Test-and-Set instruction
• Compare-and-Swap instruction
OS
19
The test_and_set Instruction
• Definition
boolean test_and_set (boolean
*target)
{
boolean rv = *target;
*target = true;
OS
return rv:
}
• Properties
• Executed atomically
• Returns the original value of passed parameter
• Set the new value of passed parameter to true
20
Solution Using test_and_set()
• Shared boolean variable lock, initialized to false
• Solution:
do {
while (test_and_set(&lock))
; /* do nothing */
/* critical section */
OS
lock = false;
/* remainder section */
} while (true);
21
The compare_and_swap
Instruction
• Definition
int compare_and_swap(int *value, int expected, int new_value)
{
OS
*value = new_value;
return temp;
}
• Properties
• Executed atomically
• Returns the original value of passed parameter value
• Set the variable value the value of the passed parameter
new_value but only if *value == expected is true. That is,
22
the swap takes place only under this condition.
Solution using
compare_and_swap
• Shared integer lock initialized to 0;
• Solution:
while (true){
while (compare_and_swap(&lock, 0, 1) != 0)
; /* do nothing */
OS
/* critical section */
lock = 0;
/* remainder section */
}
23
Bounded-waiting with compare-and-swap
while (true) {
waiting[i] = true;
key = 1;
while (waiting[i] && key == 1)
key = compare_and_swap(&lock,0,1);
waiting[i] = false;
OS
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = 0;
else
waiting[j] = false;
/* remainder section */ 24
}
Atomic Variables
• Typically, instructions such as compare-and-swap are used
as building blocks for other synchronization tools.
• One tool is an atomic variable that provides atomic
(uninterruptible) updates on basic data types such as
integers and booleans.
OS
• For example:
• Let sequence be an atomic variable
• Let increment() be operation on the atomic variable
sequence
• The Command:
increment(&sequence);
ensures sequence is incremented without interruption:
25
Atomic Variables
• The increment() function can be implemented as follows:
OS
temp = *v;
}
w h i l e ( t e m p ! =
(compare_and_swap(v,temp,temp+1));
}
26
Semaphore
• Synchronization tool that provides more sophisticated ways
(than Mutex locks) for processes to synchronize their
activities.
• Semaphore S – integer variable
• Can only be accessed via two indivisible (atomic) operations
• wait() and signal()
• Originally called P() and V()
OS
• Definition of the wait() operation
wait(S) {
while (S <= 0)
; // busy wait
S--;
}
• Definition of the signal() operation
signal(S) {
S++; 27
}
Semaphore (Cont.)
• Counting semaphore – integer value can range over an
unrestricted domain
• Binary semaphore – integer value can range only between 0
and 1
• Same as a mutex lock
• Can implement a counting semaphore S as a binary semaphore
OS
• With semaphores we can solve various synchronization problems
28
Semaphore Usage Example
• Solution to the CS Problem
• Create a semaphore “mutex” initialized to 1
wait(mutex);
CS
signal(mutex);
• Consider P1 and P2 that with two statements S1 and S2
and the requirement that S1 to happen before S2
OS
• Create a semaphore “synch” initialized to 0
P1:
S 1;
signal(synch);
P2:
wait(synch);
S 2;
29
Semaphore Implementation
• Must guarantee that no two processes can execute the
wait() and signal() on the same semaphore at the
same time
• Thus, the implementation becomes the critical section
problem where the wait and signal code are placed in the
critical section
OS
• 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
30
Problems with Semaphores
• Incorrect use of semaphore operations:
• signal(mutex) …. wait(mutex)
• wait(mutex) … wait(mutex)
OS
• Omitting of wait (mutex) and/or signal
(mutex)
OS
• Liveness refers to a set of properties that a system must satisfy
to ensure processes make progress.
• Indefinite waiting is an example of a liveness failure.
32
Liveness
• 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);
OS
... ...
signal(S); signal(Q);
signal(Q); signal(S);
OS
• Solved via priority-inheritance protocol
34
SYNCHRONIZATION EXAMPLES
Classical Problems of
Synchronization
• Classical problems used to test newly-proposed
synchronization schemes
• Bounded-Buffer Problem
• Readers and Writers Problem
• Dining-Philosophers Problem
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
Bounded Buffer Problem (Cont.)
• The structure of the producer process
while (true) {
...
/* produce an item in next_produced */
...
wait(empty);
wait(mutex);
...
/* add next produced to the buffer */
...
signal(mutex);
signal(full);
}
Bounded Buffer Problem (Cont.)
• The structure of the consumer process
while (true) {
wait(full);
wait(mutex);
...
/* remove an item from buffer to
next_consumed */
...
signal(mutex);
signal(empty);
...
/* consume the item in next consumed */
...
}
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
• Several variations of how readers and writers are considered –
all involve some form of priorities
Readers-Writers Problem (Cont.)
• Shared Data
• Data set
• Semaphore rw_mutex initialized to 1
• Semaphore mutex initialized to 1
• Integer read_count initialized to 0
Readers-Writers Problem (Cont.)
• The structure of a writer process
while (true) {
wait(rw_mutex);
...
/* writing is performed */
...
signal(rw_mutex);
}
Readers-Writers Problem (Cont.)
• The structure of a reader process
while (true){
wait(mutex);
read_count++;
if (read_count == 1) /* first reader */
wait(rw_mutex);
signal(mutex);
...
/* reading is performed */
...
wait(mutex);
read count--;
if (read_count == 0) /* last reader */
signal(rw_mutex);
signal(mutex);
}
Readers-Writers Problem
Variations
• The solution in previous slide can result in a situation where a
writer process never writes. It is referred to as the “First reader-
writer” problem.
• The “Second reader-writer” problem is a variation the first reader-
writer problem that state:
• Once a writer is ready to write, no “newly arrived reader” is allowed
to read.
• Both the first and second may result in starvation. leading to even
more variations
• Problem is solved on some systems by kernel providing reader-
writer locks
Dining-Philosophers Problem
• N philosophers’ sit at a round table with a bowel of rice in the middle.
• Semaphore Solution
• The structure of Philosopher i :
while (true){
wait (chopstick[i] );
wait (chopStick[ (i + 1) % 5] );
signal (chopstick[i] );
signal (chopstick[ (i + 1) %
5] );
}
• What is the problem with this algorithm?
POSIX Semaphores
• POSIX provides two versions – named and unnamed.
• Named semaphores can be used by unrelated processes,
unnamed cannot.
POSIX Named Semaphores
• Creating an initializing the semaphore:
• Constructor:
• Usage:
Java Condition Variables
OS 65
• Write a program to solve Producer-Consumer, Reader-Writer,
Dinning-Philosophers Problems
Thank you!
OS 66
Q&A