Transcript 5. Synch
Operating Systems
Certificate Program in Software Development CSE-TC and CSIM, AIT September -- November, 2003
5. Process Synchronization
(Ch. 6, S&G) ch 7 in the 6th ed.
Objectives – describe the synchronization problem and some common mechanisms for solving it OSes: 5. Synch 1
Contents
1.
2.
3.
4.
5.
Motivation: Bounded Buffer Critical Sections Synchronization Hardware Semaphores Synchronization Examples OSes: 5. Synch
continued
2
OSes: 5. Synch 6.
7.
8.
9.
10.
Problems with Semaphores Critical Regions Monitors Synchronization in Solaris 2 Atomic Transactions 3
1. Motivation: Bounded Buffer
0 bounded buffer
…..
1 2 3
…..
n-1 producer write read consumer OSes: 5. Synch 4
Producer Code (pseudo-Pascal)
OSes: 5. Synch : repeat . . .
/* produce an itemP */ . . .
while (counter == n) do no-op; buffer[in] := itemP; /* write */ in := (in+1) mod n; counter := counter + 1; until false; : 5
Consumer Code
OSes: 5. Synch : repeat while (counter == 0) do no-op; itemC := buffer[out]; /* read */ out := (out+1) mod n; counter := counter - 1; . . .
/* use itemC for something */ . . .
until false; : 6
Problem
Assume counter == 5 producer run : counter := counter + 1; : consumer run : counter := counter - 1; : counter may now be 4 , 5 , or 6 . Why?
OSes: 5. Synch 7
Machine Language
“counter := counter + 1” becomes: reg1 := counter reg1 := reg1 + 1 counter := reg1 “counter := counter - 1” becomes: reg2 := counter reg2 := reg2 - 1 counter := reg2 OSes: 5. Synch 8
Execution Interleaving
The concurrent execution of the two processes is achieved by interleaving the execution of each There are many possible interleavings, which can lead to different values for counter – a different interleaving may occur each time the processes are run OSes: 5. Synch 9
Interleaving Example
Initially: counter == 5 Execution: reg1 := counter reg1 := reg1 + 1 reg2 := counter reg2 := reg2 - 1 counter := reg1 counter := reg2 // reg1 == 5 // reg1 == 6 // reg2 == 5 // reg2 == 4 // counter == 6 // counter == 4 OSes: 5. Synch 10
Summary of Problem
Incorrect results occur because of a
race condition
over the modification of the shared variable ( counter ) The processes must be
synchronized
while they are sharing data so that the result is predictable and correct OSes: 5. Synch 11
2. Critical Sections
A critical section is a segment of code which can only be executed by one process at a time – all other processes are excluded – called
mutual exclusion
OSes: 5. Synch 12
Critical Section Pseudo-code
repeat entry section critical section exit section remainder section until false; OSes: 5. Synch 13
Implementation Features
An implementation of the critical section idea must have three features: – mutual exclusion – progress the next process to enter the critical region is decided solely by looking at those waiting in their entry sections – bounded waiting no process should wait forever in their entry section OSes: 5. Synch 14
2.1. Solutions for Two Processes
Algorithm 1 (take turns) – shared data: var turn: 0..1 := 0; /* or 1 */ – Code for process i: repeat while (turn /== i) do no-op: critical section; turn := j; remainder section; until false; progress requirement not met OSes: 5. Synch 15
Algorithm2
(who wants to enter?)
Shared data: var flag : array [0..1] of boolean := {false, false}; Code for process i: repeat flag[i] := true; while (flag[j]) do no-op: critical section; flag[i] := false; remainder section; until false; progress requirement still not met OSes: 5. Synch 16
Algorithm 3 (Peterson, 1981)
Combines algorithms 1 and 2 – who wants to enter?
– if both do then take turns Shared data: var flag : array [0..1] of boolean := {false, false}; var turn : 0..1 := 0; /* or 1 */ OSes: 5. Synch
continued
17
Code for process i: repeat flag[i] := true; turn := j; while (flag[j] and turn == j) do no-op: critical section; flag[i] := false; remainder section; until false; OSes: 5. Synch 18
2.2. Multiple Processes
Uses the
bakery algorithm
(Lamport 1974).
Each customer (process) receives a number on entering the store (the entry section).
The customer with the lowest number is served first (enters the critical region).
OSes: 5. Synch
continued
19
If two customers have the same number, then the one with the lowest name is served first – names are unique and ordered OSes: 5. Synch 20
Pseudo-code
Shared data: var choosing : array [0..n-1] of boolean := {false .. false}; var number : array [0..n-1] of integer := {0 .. 0};
continued
21 OSes: 5. Synch
Code for process i: repeat choosing[i] := true; number[i] := max(number[0], number[1], . . ., number[n-1]) + 1; choosing[i] := false; for j := 0 to n-1 do begin while (choosing[j]) do no-op; while ((number[j] /== 0) and ((number[j],j) < (number[i],i))) do no-op; end; critical section number[i] := 0; remainder section until false; OSes: 5. Synch 22
3. Synchronization Hardware
Hardware solutions can make software synchronization much simpler On a uniprocessor, the OS can disallow interrupts while a shared variable is being changed – not so easy on multiprocessors OSes: 5. Synch
continued
23
Typical hardware support: – atomic test-and-set of a boolean (byte) – atomic swap of booleans (bytes) Atomic means an uninterruptable ‘unit’ of work.
OSes: 5. Synch 24
3.1. Atomic Test-and-Set
function Test-and-Set( var target : boolean) : boolean begin Test-and-Set := target; target := true; end; OSes: 5. Synch 25
Use
lock/in lock/out result F T F T T T Shared data: var lock : boolean := false; action proceed loop Process code for mutual exclusion: repeat while (Test-and-Set(lock) do no-op; critical section lock := false; remainder section until false; OSes: 5. Synch 26
3.2. Atomic Swap
procedure Swap(var a, b : boolean) var temp : boolean; begin temp := a; a := b; b := temp; end; OSes: 5. Synch 27
Use
in : key1 T key2 T … … Shared data: var lock : boolean := false; OSes: 5. Synch Process code for m.e.: var key : boolean: repeat key := true; repeat Swap(lock, key); until (key == false); critical section lock := false; remainder section until false; keyN lock T F 28
3.3. Bounded Waiting
TestAndSet() and Swap() both satisfy the requirements of mutual exclusion and progress But bounded waiting is
not
satisfied We must add an extra data structure to code FIFO (queueing-style) behaviour OSes: 5. Synch 29
4. Semaphores (Dijkstra, 1965)
Semaphores are a synchronization tool based around two atomic operations: – wait() – signal() sometimes called P() sometimes called V() OSes: 5. Synch 30
4.1. Definitions
same as integer procedure wait(var S : semaphore) begin while (S =< 0) do no-op; S := S - 1; end; procedure signal(var S : semaphore) begin S := S + 1; end; OSes: 5. Synch 31
4.2. Mutual Exclusion with Semaphores
Shared data: var mutex : semaphore := 1; Process code: repeat wait(mutex); critical section; signal(mutex); remainder section; until false; OSes: 5. Synch 32
4.3. Ordering Processes
Establish a fixed order for two processes p 1 and p 2 , We set semaphore Order := 0 .
If the desired order is p 1 -> p 2 , p 2 should issue a wait(Order) , and then wait until p 1 issues a signal(Order) .
OSes: 5. Synch 33
4.4. Counting Semaphores
Allow N processes into a critical section, by initialising semaphore Limit to N – the first N processes each decrement Limit using wait(Limit) , until Limit == 0 , at which time new processes must wait This approach is used for controlling access to a limited number of resources (e.g. N resources) OSes: 5. Synch 34
4.5. Implementations
Our wait() implementation uses busy-waiting – sometimes called a
spinlock
An alternative is for the process calling wait() to
block
– place itself on a wait list associated with the semaphore – signal() chooses a blocked process to become ready OSes: 5. Synch 35
New Semaphore Data Type
type semaphore = record value : integer; L : list of waiting-processes; end; OSes: 5. Synch 36
New Operations
OSes: 5. Synch procedure wait(var S : semaphore) begin S.value := S.value - 1; if (S.value < 0) then begin /* add the calling process to S.L */ . . .
block; end; end;
continued
37
OSes: 5. Synch procedure signal(var S : semaphore) begin S.value := S.value + 1; if (S.value =< 0) then begin /* remove a process P from S.L */ . . .
wakeup(P); end; end; 38
4.6. Deadlocks & Starvation
Deadlock
occurs when every process is waiting for a signal(S) call that can only be carried out by one of the waiting processes.
Starvation
occurs when a waiting process never gets selected to move into the critical region.
OSes: 5. Synch 39
4.7. Binary Semaphores
A
binary semaphore
is a specialisation of the counting semaphore with S only having a range of 0..1
– S starts at 0 – easy to implement – can be used to code up counting semaphores OSes: 5. Synch 40
5. Synchronization Examples
5.1. Bounded Buffer 5.2. Readers and Writers 5.3. Dining Philosophers OSes: 5. Synch 41
5.1. Bounded Buffer (Again)
0 bounded buffer
…..
1 2 3
…..
n-1 producer write read consumer OSes: 5. Synch 42
Implementation
Shared data: var buffer : array[0..n-1] of Item; var mutex : semaphore := 1; /* for access to buffer */ var full : semaphore := 0; /* num. of used array cells */ var empty : semaphore := n; /* num. of empty array cells */ OSes: 5. Synch 43
Producer Code
repeat . . .
/* produce an itemP */ . . .
wait(empty); wait(mutex);
buffer[in] := itemP; in := (in+1) mod n;
signal(mutex); signal(full);
until false; OSes: 5. Synch 44
Consumer Code
OSes: 5. Synch repeat
wait(full); wait(mutex);
itemC := buffer[out]; out := (out+1) mod n;
signal(mutex); signal(empty);
. . .
/* use itemC for something */ . . .
until false; 45
5.2. Readers & Writers
Readers make no change to the shared data (e.g. a file) – no synchronization problem Writers do change the shared data Multiple writers (or a writer
and
readers) cause a synchronization problem. OSes: 5. Synch 46
Many Variations
1. Don’t keep a reader waiting unless a writer is already using the shared data – writers may starve 2. Don’t keep a writer waiting – readers may starve OSes: 5. Synch 47
Variation 1
Shared data: var shared-data : Item; var readcount : integer : = 0; /* no. of readers currently using shared-data */ var mutex : semaphore := 1; /* control access to readcount */ var wrt : semaphore := 1; /* used for m.e. of writers */ OSes: 5. Synch 48
Writer’s Code
:
wait(wrt);
. . .
/* writing is performed */ . . .
signal(wrt);
: OSes: 5. Synch 49
Reader’s Code
wait(mutex);
readcount := readcount + 1; if (readcount == 1) then
wait(wrt)
;
signal(mutex);
. . .
/* reading is performed */ . . .
wait(mutex);
readcount := readcount - 1; if (readcount == 0) then
signal(wrt)
;
signal(mutex);
OSes: 5. Synch 50
5.3. Dining Philosophers
Dijkstra, 1965 An example of the need to allocate several resources (chopsticks) among processes (philosophers) in a deadlock and starvation free manner.
OSes: 5. Synch 51
Implementation
Represent each chopstick by a semaphore.
Shared data: var chopstick : array[0..4] of semaphore := {1,1,1,1,1}; A chopstick is ‘picked up’ with: wait(chopstick[pos]) and ‘set down’ with: signal(chopstick[pos]) OSes: 5. Synch 52
Code for Philopospher i
OSes: 5. Synch repeat
wait( chopstick[i] ); wait( chopstick[(i+1) mod 5] );
/* . . . eat . . . */
signal( chopstick[i] ); signal( chopstick[(i+1) mod 5] );
/* . . . think . . . */ until false; 53
Deadlock
This solution avoids simultaneous use of chopsticks (
good
) But if all the philosophers pick up their left chopstick together, then they will
deadlock
while waiting for access to their right chopstick.
OSes: 5. Synch 54
Possible Fixes
Allow at most 4 philosophers to be at the table at a time.
Have a philosopher pick up their chopsticks only if both are available (in a critical section) Alternate the order that chopsticks are picked up depending on whether the philosopher is seated at an odd or even seat OSes: 5. Synch 55
6. Problems with Semaphores
The reversal of a wait() and signal() pair will break mutual exclusion The omission of either a wait() or signal() will potentially cause deadlock These problems are difficult to debug and reproduce OSes: 5. Synch 56
Higher level Synchronization
These problems have motivated the introduction of higher level constructs: – critical regions – monitors – condition variables These constructs are safer, and easy to understand OSes: 5. Synch 57
7. Critical Regions
Hoare, 1972; Brinch Hansen, 1972 Shared variables are explicitly declared: var v :
shared
ItemType; A shared variable can only be accessed within the code part ( S ) of a region statement: region v do S – while code S is being executed, no other process can access v OSes: 5. Synch 58
Conditional Critical Regions
region v when B do S – only execute S when the boolean expression B evaluates to true, otherwise wait until B is true – as before, while code S is being executed, no other process can access v OSes: 5. Synch 59
Bounded Buffer Again
Shared data: var buffer :
shared
record pool : array[0..n-1] of Item; count, in, out : integer; end; OSes: 5. Synch 60
Producer Code
region buffer when (count < n) do begin pool[in] := itemP; in := (in+1) mod n; count := count + 1; end; OSes: 5. Synch 61
Consumer Code
region buffer when (count > 0) do begin itemC := pool[out]; out := (out+1) mod n; count := count - 1; end; OSes: 5. Synch 62
8. Monitors
queues associated with condition variables var shared data Brinch Hansen, 1973 entry queue of waiting processes Fig. 6.20, p.184
OSes: 5. Synch operations initialization code 63
Monitor Syntax
type monitor-name = monitor variable declarations procedure entry p1(. . .) begin . . . end; : begin initialization code end.
OSes: 5. Synch 64
Features
When an instance of a monitor is created, its initialization code is executed A procedure can access its own variables and those in the monitor’s variable declarations A monitor only allows one process to use its operations at a time OSes: 5. Synch 65
An OO View of Monitors
A monitor is similar to a class An instance of a monitor is similar to an object, with all private data
Plus
synchronization: invoking any operation (method) results in mutual exclusion over the entire object OSes: 5. Synch 66
8.1. Condition Variables
Notation: var x : condition; x.wait; suspend calling process x.signal; resumes one of the suspended processes waiting on x OSes: 5. Synch 67
Condition Variables in Monitors
What happens when signal is issued?
The unblocked process will be placed on the ready queue and resume from the statement following the wait .
This
would
violate mutual exclusion
if
both the signaller and signalled process are executing in the monitor at once.
OSes: 5. Synch 68
Three Possible Solutions
1. Have the signaller leave the monitor immediately after calling signal 2. Have the signalled process wait until the signaller has left the monitor 3. Have the signaller wait until the signalled process has left the monitor OSes: 5. Synch 69
8.2. Dining Philosophers (Again)
Useful data structures: var state : array[0..4] of (thinking, hungry, eating); var self : array[0..4] of condition; /* used to delay philosophers */ The approach is to only set state[i] to eating if its two neigbours are not eating – i.e. and state[(i+4) mod 5] = state[(i+1) mod 5] = eating eating OSes: 5. Synch 70
Using the dining-philosophers Monitor
Shared data: var dp : dining-philosopher; Code in philosopher i: dp.pickup(i): /* . . . eat . . . */ dp.putdown(i); OSes: 5. Synch 71
Monitor implementation
type dining-philosophers = monitor var state : array[0..4] of (thinking, hungry, eating); var self : array[0..4] of condition; OSes: 5. Synch procedure entry pickup(i : 0..4) begin state[i] := hungry; test(i); if (state[i] /== eating) then self[i].wait; end;
continued
72
OSes: 5. Synch procedure entry putdown(i : 0..4) begin state[i] := thinking; test((i+4) mod 5); test((i+1) mod 5); end;
continued
73
OSes: 5. Synch procedure test(k : 0..4) begin if ((state[(k+4) mod 5] /== eating) and (state[k] == hungry) and (state[(k+1) mod 5] /== eating)) then begin state[k] := eating; self[k].signal; end; end;
continued
74
OSes: 5. Synch begin /* initialization of monitor instance */ for i := 0 to 4 do end.
state[i] := thinking; 75
8.3. Problems with Monitors
Even high level operations can be misused.
For correctness, we must check: – that all user processes always call the monitor operations in the right order; – that no user process bypasses the monitor and uses a shared resource directly – called the
access-control problem
OSes: 5. Synch 76
9. Synchronization in Solaris 2
Uses a mix of techniques: – semaphores using spinlocks – thread blocking – condition variables (without monitors) – specialised reader-writer locks on data OSes: 5. Synch 77
10. Atomic Transactions
We want to do all the operations of a critical section as a single logical ‘unit’ of work – it is either done completely or not at all A transaction can be viewed as a sequence of read s and write s on shared data, ending with a commit or abort operation An abort causes a partial transaction to be OSes: 5. Synch
rolled back
78
10.1. Log-based Recovery
Atomicity is ensured by logging transaction operations to stable storage – these can be replayed or used for rollback if failure occurs Log details: – transaction name, data name, old value, new value OSes: 5. Synch
continued
79
Write-ahead logging: – log a write operation
before
doing it – log the transaction start and its commit OSes: 5. Synch 80
Example
begin transaction read X if (X >= a) then { read Y X = X - a Y = Y + a write X write Y } end transaction (VUW CS 305)
Recovery
Operations: – – undo( Transaction i ) redo( Transaction i ) Possible states of Transaction i – committed, but were new values written?
– aborted, but were old values restored?
– unfinished OSes: 5. Synch 82
10.2. Checkpoints
A checkpoint fixes state changes by writing them to stable storage so that the log file can be reset or shortened.
OSes: 5. Synch 83
10.3. Concurrent Atomic Transactions
We want to ensure that the outcome of concurrent transactions are the same as if they were executed in some serial order –
serializability
OSes: 5. Synch 84
A Serial Schedule
Transaction 0 read A write A read B write B Fig. 6.23, p.195
Transaction 1 read A write A read B write B OSes: 5. Synch 85
Conflicting Operations
Two operations in different transactions conflict if they access the same data and one of them is a write .
Serializability must avoid conflicting operations: – it can do that by delaying/speeding up when operations in a transaction are performed OSes: 5. Synch 86
A Concurrent Serializable Schedule
Fig. 6.24, p.196
Transaction 0 read A write A Transaction 1 read A write A read B write B read B write B OSes: 5. Synch 87
10.4. Locks
Serializability can be achieved by locking data items There are a range of locking modes: – a
shared lock
allows multiple reads by different transactions – an
exclusive lock
allows only one transaction to do reads/writes OSes: 5. Synch 88
10.5. Timestamping
One way of ordering transactions Using the system clock is not sufficient when transactions may originate on different machines OSes: 5. Synch 89