ch5-6 - Susan V. Vrbsky

advertisement

Chapter 6 Process Synchronization

Cooperating and Concurrent Processes: executions overlap in time and they need to be synchronized

Synchronization is necessary for:

multiprogrammed uniprocessor

uniprocessor and I/O processor

shared memory multiprocessor

non-shared memory systems (distributed environments)

Support for Synchronization: hardware: interrupts (shared memory support) atomic machine instructions (shared memory support) e.g. SUB R1, x

Test and Set (shared memory support)

operating system software (shared memory support) semaphores (shared memory support) message passing (non-shared memory support)

programming languages monitors (shared memory support)

Concurrent Pascal, Modula, Mesa, Concurrent Euclid path expressions (shared memory support)

Path Pascal

RPC/rendezvous(non-shared memory support)

ADA(DOD) for rendezvous

Example: Producer/Consumer problem bounded buffer holds n items no guarantee on relative speeds producer uses IN to keep track of next place to put item

consumer uses OUT to keep track of next place to take item from

if look at code, only (n-1) buffers can be used at a time

add count in order to remedy problem

both use count to know how many items are in buffer

18

in consumer: count--

LD R2, Count

SUB R2, 1

ST R2, Count

in producer: count++

LD R4, Count

ADD R4, 1

ST R4, Count

Race Condition - outcome depends on order in which instructions executed this should NOT be the case for example, what if context switch after loading of count value? need two instructions to be executed ATOMICALLY but only guaranteed that the machine instructions are atomic

The Critical Section (CS) Problem n processes competing to use some shared data

no assumption allowed on relative speeds of the n processes

CS is a segment of code which contains shared data only one process can be in its CS at a time each CS execution must be mutually exclusive (mutex)

mutual exclusion occurs if a process is in its CS, no other process is

entry to CS

CS

exit from CS

other code

Correctness: mutual exclusion - if a process is in CS, no other process in CS progress - if a process wants to enter CS decision not based on processes in other code section above bounded waiting - finite bound of number of times other process gets into CS once you request to get in therefore no: starvation - there exist a process who never gets into CS deadlock - two or more processes waiting for an event that won't occur

19

Software Solutions

Suppose two processes P2 and P3 both execute the same code to access critical section

Solution 1: assume use a shared-memory variable boolean FLAG to enforce mutual exclusion initially FLAG = F

Process 2 repeat

Process 3 repeat while (FLAG)busy wait; while (FLAG) busy wait;

FLAG = T; FLAG = T;

critical section; critical section;

FLAG = F; FLAG = F; other code; forever; other code; forever; doesn't enforce mutual exclusion

Solution 2: assume TURN(2..3) is a shared-memory variable that keeps track of whose turn it is assume TURN is initially 2

Process 2 repeat

Process 3 repeat while (TURN != 2) busy wait; while (TURN != 3) busy wait;

critical section; critical section;

TURN = 3; TURN = 2; other code; other code; forever; forever; enforces mutual exclusion strictly alternating not a good idea if one process is slower blocked by a process not in its critical section - violates progress

20

Solution 3: assume shared memory variables FLAG: array [2..3] of boolean assume FLAG is initially F

Process 2 repeat

Process 3 repeat

FLAG[2] = T; FLAG[3] = T; while (FLAG[3]) busy wait; while (FLAG[2]) busy wait;

critical section; critical section;

FLAG[2] = F; FLAG[3] = F; other code; other code; forever; forever; satisfies mutual exclusion deadlock - P2 and P3 can wait forever

Solution 4: use the same shared-memory variables as Solution 3 additional usage of FLAG variables - initially F

Process 2 repeat

Process 3 repeat

FLAG[2] = T; while (FLAG[3])

FLAG[3] = T; while (FLAG[2])

{ FLAG[2] = F; { FLAG[3] = F; delay; delay;

FLAG[2] = T; FLAG[3] = T;

} }

critical section; critical section;

FLAG[2] = F; FLAG[3] = F; other code; forever; other code; forever; can have indefinite postponement - starvation one process can monopolize the CPU

21

Solution 5: use the same shared-memory variables as Solutions 3 and 4 add the shared-memory variable TURN(2..3) to indicate which process

Process 2 repeat

Process 3 repeat

FLAG[2] = T;

TURN = 3;

FLAG[3] = T;

TURN = 2; while (FLAG[3]) and while (FLAG[2]) and

(TURN = 3) busy wait; (TURN = 2) busy wait;

critical section; critical section;

FLAG[2] = F; FLAG[3] = F; other code; forever; other code; forever; satisfies mutual exclusion satisfies bounded waiting

Peterson's solution (1981) similar to Dekker's (1965) more complex

Solves the problem for TWO processes only

Consider n processes that want CS access

Bakery Algorithm: before entering CS, get a number holder of the smallest number enters the CS number[i] = max.(number[0], number[1], ..number[n-1]) + 1 numbers generated in increasing order of enumeration:1,2,3,3,3,4,5,5,6 if number[i] = number[j], then if (i<j), then pi is served first else Pj is served first

Bakery Algorithm from Lamport 1974 - see text for details

Disadvantages of all software solutions cumbersome busy wait difficult to extend to n processors

22

Semaphores: Dijkstra 1965

A semaphore is a synchronization tool that doesn't require busy waiting

A semaphore s is an integer variable and a queue of processes semaphore is accessible by two ATOMIC ops

P = probern = WAIT; V = verhogun = SIGNAL

P(s); s--;

/* wait */

if s < 0 then block(s);

V(s); s++;

/* signal */

if s <= 0 then wakeup(s)

block(s) - suspend process invoking it (wait) - place process on queue for s

wakeup(s) - resume one process - remove process from s queue place on ready queue simple powerful: can solve wide variety of synchronization problems doesn't require a busy wait

Critical Section Problem: Solution for n Processes

Solution 6: var mutex: semaphore = 1;

Process i repeat

P(mutex);

critical section;

V(mutex);

other code;

Process j repeat

P(mutex);

critical section;

V(mutex); other code;

forever; forever; mutex = 1 means there's no one in CS and no one waiting to get in mutex = 0 means there is one process in CS mutex < 0 means many processes waiting to get into CS satisfies mutual exclusion

23

satisfies bounded waiting satisfies progress

Implementation of P and V

1. uniprocessor environment: need to maintain a queue of process's PCBs waiting with block, add PCB to linked list with signal, choose process from list(most likely FCFS)

P and V are themselves critical sections! need P and V to be atomic inhibit interrupts around the P and V code disable all interrupts code for P or V enable all interrupts

if test-and-set available (hardware solution), use it

2. multiprocessor environment:

if no special hardware, use correct software solution with P/V disable all interrupts;

Peterson's entry code

code for P or V

Peterson's exit code enable all interrupts

Semaphore Types binary semaphore: integer value can only be 0 and 1 counting semaphore: integer value can range over an unrestricted range can implement a counting semaphore as a binary semaphore need multiple binary semaphores and a counting integer

Mutual Exclusion using binary semaphores

See Solution 6 above

24

Synchronization - using binary semaphores

P and V solves precedence relations of who goes next as a general synchronization tool suppose up to code S1 in P1 must finish before S2 in P2 begins shared variable synch: semaphore = 0;

P1 P2 repeat other code;

V(synch); /* Send */ code S1; repeat other code;

P(synch); /* Receive */ code s2; forever; forever;

Multiple Access in Critical Section using couting semaphores

Can use P and V to allow more than one process access resource suppose have 5 printers, then 5 processes can print

Example: need a way to regulate people in room, only three chairs available

shared variable count: semaphore = 3;

Person comes to door

P(count);

comes into room and takes an available chair

sits for a while

exits room

V(count);

3 processes can be in CS at the same time

Can use semaphores for the producer/consumer problem changing the value of counter shared var buffer: array[1..n] of whatever shared var counter: integer = 0; shared var s: semaphore = 1;

Producer/Consumer Problem: Solution 1

Producer repeat

Consumer

repeat

25

while (counter == n) do no-op; while(counter==0) do no-op;

buffer[in] = next item; consumer item in buffer[out];

in++; (mod n) out++; (mod n)

P(s); P(s); counter++;

V(s); forever; counter-;

V(s); forever;

PROBLEM: busy wait yuck!

Reader/Writer Problem: Solution 1 shared information reader: read only writer: read and write (must have exclusive access) shared-var mutex: semaphore = 1; shared-var wrt: semaphore = 1; shared-var readcount: integer = 0;

Reader Writer (only one writer at a time) repeat

P(mutex); readcount++; if readcount = 1 then P(wrt); repeat

P(wrt); forever;

..writing is performed...

V(wrt);

V(mutex);

..reading is performed...

P(mutex); readcount--; if readcount = 0 then V(wrt);

V(mutex); forever;

who had priority in accessing data? readers

no reader will be kept waiting unless a writer has attained permission

Dining Philosophers Problem: Solution 1 each philosopher thinks and then eats then thinks pick up left chopstick, then pick up right chopstick

26

shared var chopstick: array[0..4] of semaphore = 1 repeat

P(chopstick[i]);

P(chopstick[i+1 mod 5]);

..eat...

V(chopstick[i]);

V(chopstick[i+1 mod 5]);

..think.. forever;

Problem: deadlock possible

Dining Philosophers Problem: Solution 2 each philosopher thinks and then eats then thinks... need two chopsticks to eat pick up left chopstick, if right not available, put down left

loop until are holding both, then eat shared var chopstick: array[0..4] of semaphore = 1 repeat repeat

P(chopstick[i]); /* pick up left */ if (right not available) then V(chopstick[i]); else P(chopstick[i+1 mod 5]); until holding both;

..eat ...

V(chopstick[i]);

V(chopstick[i+1 mod 5]);

...think... forever;

problem: starvation

Dining Philosophers Problem: Solution 3 only allow four philosophers to be in the room at a time shared var chopstick: array[0..4] of semaphore = 1 shared var room: semaphore = 4;

27

repeat

P(room);

P(chopstick[i]);

P(chopstick[i+1 mod 5]);

..eat ...

V(chopstick[i]);

V(chopstick[i+1 mod 5]);

V(room);

...think ... forever;

WORKS!

Possible Problems with Semaphore

Semaphores are prone to user errors! e.g. switching P's and V's perhaps better to have higher level programming language constructs monitors

Starvation is possible depending on the scheduling algorithm for removing processes from waiting list a process may never be removed from the semaphore "queue"

Deadlock - if don't have synchronization specified correctly

Example: shared variables S, Q: semaphores

each initially = 1

P2 P1 repeat

P(S); repeat

P(Q);

P(Q);

...

V(S);

V(Q);

forever;

P(S);

...

V(Q);

V(S); forever;

Critical regions: high level synchronization construct

shared var count: integer region count do S1;

28

region count do S2; compiler will generate P and V to be sure S1 and S2 are mutual exclusive

P(count:mutex) ... S1 ... V(count:mutex)

Hardware Solutions to CS problem

Disable interrupts - simplest solution allow no clock interrupts problems users will abuse (its OK for kernel but not user level processes) if 2 or more CPUs, other CPUs not affected

Computer manufacturers design hardware with special machine instructions instructions specifically for the CS problem - Test-and-Set instruction

Test-and-Set is: atomic instruction

copies the value in MEM to register REG sets MEM = 1 (True) think of test-and-set as the following function: function test-and-set (var mem: Boolean): Boolean begin indivisible

test-and-set := mem;

mem:= True;

end indivisible that maps to the following single assembly language instruction:

TandS REG, MEM

CS problem can be solved with this hardware shared memory LOCK: Boolean = False;

while (test-and-set(LOCK)) no-op; /* busy wait */

critical section

LOCK = false;

satisfies mutual exclusion because test-and-set is atomic;

satisfies progress bounded wait? NO!

29

to get bounded wait, solution twice as long - see textbook

Disadvantages of hardware solutions busy wait - spinlock spins while waiting for lock - useful in mulitprocessor context no context switch required - which takes up time useful if wait for lock only a short amount of time not applicable to computers without these special functions not able to solve more complex synchronization problems

Can implement binary semaphores using test-and-set

P (S : semaphore);

{ while test-and-set(S) do no-op;

}

V (S : semaphore);

{

S = false;

}

Monitors: Hoare 1974

High-level synchronization tool available in lots of programming languages:

First used by Concurrent Pascal (Brinch Hansen 1975)

Modula (Wirth 1979)

Concurrent Euclid (Holt)

Abstract data type with capabilities for synchronization

ADT: module that encapsulates

data (representing resources)

private procedures

public procedures

public interface

data manipulated through public interface which uses private interface

internal implementation of ADT is unknown to the user

all components of the monitor are encapsulated in the monitor structure resource, procedure, initialization code, etc.

Monitors and synchronization:

30

Only one process in a monitor at a time - mutual exclusion

condition variables - for additional synchronization suppose x: condition; is a local data structure

wait(cond): the process that executes this instruction gets suspended the process waits on a queue associated with condition x releases mutual exclusion to another

signal(cond): the process that executes this instruction blocks some require signal to be last instruction in monitor process from queue gets to execute in monitor if queue is empty, no effect from signal - this is different from a semaphore

Processes in the condition queue may be organized according to

* FCFS

* priority

* other scheduling disciplines when process calls x.wait another process allowed in monitor

Example: counter

/* Monitor counter; */ type counter = monitor; var count:integer; procedure entry incr; begin count++; end procedure entry decr; begin count--; end begin count = 0; end

/* end monitor; */

/* initialization */ in programs that need access to shared counter: var total: counter; /* declaring total as a monitor */

...

31

total.incr;

... total.decr;

Example: Producer and Consumer

/* Monitor buffer; */ type buffer: monitor; var type buf = array[0..(n-1)] of item; head, tail, counter:integer; empty, full: condition; procedure entry deposit(x:item); begin if (counter == n) then full.wait; buf[tail] = x; tail = (tail+1) mod n; counter++; empty.signal; /* if no one waiting, nothing happens */ end procedure entry remove(y:item); begin if (counter == 0) then empty.wait; y = buf[head]; head = (head+1) mod n; counter--; full.signal; end begin /* initialization */ counter = 0; head = 0; tail = 0; end

/* end monitor; */

Producer (void); var item_pr : buffer; data : item; repeat item_pr.enter(data); forever;

32

Consumer (void); var item_cons : buffer; data : item; repeat item_cons.remove(data); forever;

Examples in text: dining philosophers solution with monitors resource allocation solution with monitors one resource that requires mutual exclusive access

Monitors are equivalent in power to P and V can implement semaphores with monitors can implement monitors with semaphores text shows how to implement monitors with semaphores read carefully if not sure equivalent power

Disadvantages of monitors: if resource being access outside of monitor depends on correct use of entry procedures if using monitor to control access for reader/writer problem only one reader allowed to access shared data (only one in monitor) nested monitor calls: monitor procedure calls monitor procedure calls... deadlock and efficiency problems possible one solution: whenever block in a monitor temporarily release ownership of all monitors (increase bookkeeping, but necessary and flexible) second solution: inner monitors ensure processes wait only a short time queue handling is not clearly defined

Skip the rest of the text

33

Download