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) OSes: 5. Synch 81

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