720 likes | 850 Views
Process Synchronization. Concurrent access to shared data may result in data inconsistency We must have mechanisms to ensure the orderly execution of cooperating processes
E N D
Process Synchronization • Concurrent access to shared data may result in data inconsistency • We must have mechanisms to ensure the orderly execution of cooperating processes • Suppose we consider the bounded buffer problem and add a variable, counter, initialized to 0 and incremented each time a new item is added to the buffer
Bounded Buffer • Shared data typeitem = …; varbuffer: array[0..n-1]ofitem; in, out: 0..n-1; counter: 0..n; in, out, counter := 0;
Bounded Buffer (cont) • Producer process repeat … produce an item in nextp … whilecounter = ndono-op; buffer[in] := nextp; in := (in + 1)modn; counter := counter + 1; untilfalse;
Bounded Buffer (cont) • Consumer process repeat whilecounter = 0dono-op; nextc := buffer[out]; out := (out + 1)modn; counter := counter – 1; … consume the next item in nextc ... untilfalse;
Bounded Buffer (cont) • The statements that increment and decrement the counters have to be executed atomically • Atomically means that they cannot be interrupted in their execution • What happens if they are not executed atomically?
Bounded Buffer (cont) • Race condition – several processes access and manipulate the same data concurrently, and the outcome of the execution depends on the particular order in which the access takes place
Critical Section Problem • n processes all competing to use some shared data • Each process has a code segment, call the critical section, in which shared data is accessed • Problem – ensure that processes cannot execute their critical sections at the same time
Requirements for Solution to Critical Section Problem 1. Mutual Exclusion – if process Pi is executing in the critical section, no other processes can be executing in their critical sections 2. Progress – if no process is executing in its critical section and there is some process waiting to enter the critical section, the waiting process will not be postponed indefinitely
Requirements for Solution to Critical Section Problem (cont) • 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 and before that request is granted • Assume that each process executes at a nonzero speed • No assumption is made about the relative speed of the n processes
Critical Section Problem (cont) • Requirements of the solution: • Does not rely on any assumptions concerning the hardware instructions • Does not rely on the number of processes • We assume some underlying machine language for the computer we are running on
Critical Section Problem (cont) • Structure of process Pi repeat entry section critical section exit section remainder section untilfalse;
Attempts to Solve Problem • Only 2 processes, P0 and P1 • General structure of processes is as seen before • Processes may share some common variables to synchronize their actions.
Algorithm 1 • Shared variables: varturn: 0..1; initially turn = 0 turn = i Pi can enter critical section • Process P0 repeat whileturn 0 dono-op; critical section turn := 1; remainder section untilfalse; • Satisfies mutual exclusion, but not progress
Algorithm 2 • Shared variables: varflag: array[0..1] ofboolean; initially flag[0] = flag[1] = 0 flag[i] = true Pi ready to enter critical section • Process P0 repeat flag[0] := true; whileflag[1]dono-op; critical section flag[0] := false; remainder section untilfalse; • Satisfies mutual exclusion, but not progress
Algorithm 3 • Combine shared variables of algorithm 1 and 2 • Process P0 repeat flag[0] := true; turn := 1; while (flag[1]and turn = 1) dono-op; critical section flag[0] := false; remainder section untilfalse; • Meets all three requirements
Bakery Algorithm Critical section for n processes • Before entering its critical section, process receives a number. Holder of the smallest number enters the critical section • If processes Pi and Pj receive the same number, if i < j, then Pi is served first; else Pj is served first
Bakery Algorithm (cont) • The numbering scheme always generates numbers in increasing order of enumeration; i.e., 1,2,3,3,3,3,4,5,… • Notation lexicographical order (ticket#, process id#) • (a,b) < (c,d) if a < c or if a = c and b < d • max(a0,…,an-1) is a number, k, such that k ai for i = 0, …, n-1
Bakery Algorithm (cont) • Shared data • varchoosing: array [0..n-1] ofboolean; • varnumber: array [0..n-1] ofinteger; • The above data structures are initialized to false and zero, respectively
Bakery Algorithm (cont) repeat choosing[i] := true; number[i] := max(number[0], …, number[n-1]) + 1; choosing[i] := false; forj := 0 ton-1 do begin whilechoosing[j] do no-op; whilenumber[j] 0 and (number[j],j) < (number[i],i) do no-op; end; critical section number[i] := 0; remainder section untilfalse;
Synchronization Hardware • Test and modify the contents of a word atomically functionTest-and-Set(vartarget: boolean): boolean; begin Test-and-Set := target; target := true; end;
Mutual Exclusion with Test-and-Set • Shared data: varlock: boolean := false • Process Pi repeat whileTest-and-Set(lock) dono-op; critical section lock := false; remainder section untilfalse;
Semaphore • Synchronization tool that does not require busy waiting. • Semaphore S – integer variable • Can only be accessed via two indivisible (atomic) operations: • wait(S): whileS 0 dono-op; S := S – 1; • signal(S): S := S + 1;
Critical Section for n Processes • Shared variable: varmutex: semaphore := 1; • Process Pi repeat wait(mutex); critical section signal(mutex); remainder section untilfalse;
Semaphore Implementation • Define a semaphore as a record typesemaphore = record value: integer; L: list ofprocess; • Assume two simple operations: • block suspends the process that invokes it • wakeup(P) resumes the execution of a blocked process P
Implementation (cont) • Semaphore operations are now defined as • wait(S): S.value := S.value – 1; ifS.value < 0 then add this process to S.L; block; end; • signal(S): S.value := S.value + 1; ifS.value 0 then remove a process P from S.L; wakeup(P); end;
Semaphore as General Synchronization Tools • Execute B in Pj after A executed in Pi • Use semaphore flag initialized to 0 • Code Pi Pj ... … A wait(flag) signal(flag) B
Deadlock • Deadlock – two or more processes 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 P0P1 wait(S) wait(Q) wait(Q) wait(S) … … signal(S) signal(Q) signal(Q) signal(S)
Starvation • Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended.
Types of Semaphores • 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 • Can implement a counting semaphore S as a binary semaphore
Implementing a Counting Semaphore • Shared data: varS1: binary semaphore; S2: binary semaphore; C : integer; • Initialization S1 = 1 S2 = 0 C = initial value of semaphore S
Counting Semaphore (cont) • Wait wait(S1); C := C – 1; ifC < 0 thensignal(S1); wait(S2); signal(S1); • Signal wait(S1); C := C + 1; ifC 0 thensignal(S2); elsesignal(S1);
Classical Problems of Synchronization • Bounded buffer problem • Readers and writers problem • Dining philosophers problem
Bounded Buffer Problem • Shared data typeitem = … varbuffer = … full, empty, mutex: semaphore; nextp, nextc: item; full := 0; empty := n; mutex = 1;
Producer Process repeat … produce an item in nextp … wait(empty); wait(mutex); … add nextp to buffer … signal(mutex); signal(full); untilfalse;
Consumer Process repeat wait(full); wait(mutex); … remove an item from buffer to nextc … signal(mutex); signal(empty); … consume the item in nextc … untilfalse;
Readers and Writers Problem • Shared data varmutex, wrt: semaphore = 1; readcount: integer = 0; • Writer Process wait(wrt); … writing is performed … signal(wrt);
Reader Process wait(mutex); readcount := readcount + 1; ifreadcount = 1 thenwait(wrt); signal(mutex); … reading is performed … wait(mutex); readcount := readcount – 1; ifreadcount = 0 thensignal(wrt); signal(mutex);
Dining Philosophers Problem • Shared data varchopstick: array [0..4] ofsemaphore = 1;
Dining Philosophers Problem (cont) • Philosopher i: repeat wait(chopstick[i]); wait(chopstick[(i+1) mod 5]); … eat … signal(chopstick[i]); signal(chopstick[(i+1) mod 5]); … think … untilfalse;
Dining Philosopher (cont) • The previous solution has a problem – it can deadlock if both philosophers pick up their left fork at the same time. • There are solutions to this problem, but we won’t consider them at this time.
Critical Regions • High level synchronization construct • A shared variable v of type T is declared as: varv: sharedT • Variable v accessed only inside statement: regionvwhenBdoS where B is a boolean expression • While statement S is being executed, no other process can access variable v
Critical Regions (cont) • Regions referring to the same shared variable exclude each other in time • When a process tries to execute the region statement, the boolean expression B is evaluated. If B is true, statement S is executed. If B is false, the process is delayed until B becomes true and no other process is in the region associated with v.
Bounded Buffer • Shared variable varbuffer : sharedrecord pool: array[0..n-1] ofitem; count, in, out : integer; end • Producer process regionbufferwhencount < n do pool[in] := nextp; in := (in + 1) modn; count := count + 1; end;
Bounded Buffer (cont) • Consumer process regionbufferwhencount > 0 do nextc := pool[out]; out := (out + 1) modn; count := count – 1; end;
Implementation of Critical Regions • Associate with the shared variable v the following variables: varmutex, first-delay, second-delay: semaphore; first-count, second-count; integer; • Mutually exclusive access to the critical section is provided by mutex.
Implementation of CR (cont) • If a process cannot enter the critical section because the boolean expression B is false, it initially waits on the first-delay semaphore; moved to the second-delay semaphore before it is allowed to reevaluate B • Keep track of the number of processes waiting on first-delay and second-delay with first-count and second-count, respectively
Implementation of CR (cont) • The algorithm assumes a FIFO ordering on the queuing of processes for a semaphore • For an arbitrary queuing discipline, a more complicated implementation is required
Implementation of CR (cont) wait(mutex); S; whilenot B doiffirst-count > 0 first-count := first-count + 1; thensignal(first-delay) ifsecond-count > 0 else thensignal(second-delay) ifsecond-count > 0 elsesignal(mutex); thensignal(second-delay) wait(first-delay); elsesignal(mutex); first-count := first-count – 1; second-count := second-count + 1; iffirst-count > 0 thensignal(first-delay) elsesignal(second-delay); wait(second-delay); second-count := second-count – 1; end;
Monitors • High level synchronization construct that allows the safe sharing of an abstract data type among concurrent processes typemonitor-name = monitor variable declarations procedureentry P1 ( … ); begin … end; … procedureentryPn ( … ); begin … end; begin initialization code end.
Monitors (cont) • To allow a process to wait within the monitor, a condition variable must be declared as: varx,y: condition • Condition variable can only be used with the operations below: • x.wait – the process invoking this operation is suspended until another process invokes x.signal • x.signal – resumes exactly one suspended process. If no process is suspended, then the signal operation has no effect.