Outline • Announcements • Basic Synchronization Principles – continued – Semaphores – Bounded-buffer problem – Read-writer’s problem Please turn in Homework #2 Announcements • The second quiz will be at the end of class on this Thursday – October 9, 2003 – It will be closed-book and closed-note – It will cover the materials until today with emphasis on scheduling – It requires to compute average wait time and turnaround time (or something like that) and you need a calculator 5/29/2016 COP4610 2 Announcements – cont. • Demonstration of Lab 1 – You can sign up to demonstrate your program tomorrow during the recitation session – During the demo, Mr. Chen will ask you questions besides demonstration 5/29/2016 COP4610 3 Comments on Scheduling Algorithms Process Arrival Time Burst Time P1 0.0 7 P2 2.0 4 P3 4.0 1 P4 5.0 4 • Wait time and turnaround time • Round robin – Where should we place the newly arrived ones? 5/29/2016 COP4610 4 Interacting Processes - review • Independent process – Cannot affect or be affected by the other processes in the system – Does not share any data with other processes • Interacting process – Can affect or be affected by the other processes – Shares data with other processes – We focus on interacting processes through physically or logically shared memory 5/29/2016 COP4610 5 Bounded-Buffer – review 5/29/2016 COP4610 6 Bounded-Buffer - cont. • Suppose we have one producer and one consumer, the variable counter is 5 – Producer: counter = counter +1 P1: load counter, r1 P2: add r1, #1, r2 P3: store r2, counter – Consumer: counter = counter - 1 C1: load counter, r1 C2: add r1, #-1, r2 C3: store r2, counter 5/29/2016 COP4610 7 Bounded-Buffer - cont. • A particular execution sequence – P1: load counter, r1 – P2: add r1, #1, r2 --- Context switch ---– C1: load counter, r1 – C2: add r1, #-1, r2 – C3: store r2, counter --- Context switch ---– P3: store r2, counter – What is the value of counter? 5/29/2016 COP4610 8 Bounded-Buffer - cont. • A particular execution sequence – C1: load counter, r1 – C2: add r1, #-1, r2 --- Context switch ---– P1: load counter, r1 – P2: add r1, #1, r2 – P3: store r2, counter --- Context switch ---– C3: store r2, counter – What is the value of counter this time? 5/29/2016 COP4610 9 Bounded-Buffer - cont. • A particular execution sequence – C1: load counter, r1 – C2: add r1, #-1, r2 – C3: store r2, counter --- Context switch ---– P1: load counter, r1 – P2: add r1, #1, r2 – P3: store r2, counter --- Context switch ---– What is the value of counter this time? 5/29/2016 COP4610 10 Race Condition • Race condition – When several processes access and manipulate the same data concurrently, there is a race among the processes – The outcome of the execution depends on the particular order in which the access takes place – This is called a race condition 5/29/2016 COP4610 11 Traffic Intersections 5/29/2016 COP4610 12 A Semaphore 5/29/2016 COP4610 13 The Critical-Section Problem • n processes all competing to use some shared data • Each process has code segments, called critical section, in which the shared data is accessed. • Problem – ensure that when one process is executing in its critical section, no other process is allowed to execute in its critical section, called mutual exclusion 5/29/2016 COP4610 14 The Critical-Section Problem – cont. • Structure of process Pi repeat entry section critical section exit section reminder section until false; 5/29/2016 COP4610 15 Requirements for Critical-Section Solutions • Mutual Exclusion. – If process Pi is executing in its critical section, then no other processes can be executing in their critical sections. • Progress – If no process is executing in its critical section and there exist some processes that wish to enter their critical section, then the selection of the processes that will enter the critical section next cannot be postponed indefinitely. • 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. 5/29/2016 COP4610 16 Solution through Disabling Interrupts • In a uni-processor system, an interrupt causes the race condition – The scheduler can be called in the interrupt handler, resulting in context switch and data inconsistency 5/29/2016 COP4610 17 Solution through Disabling Interrupts – cont. • Process Pi repeat disableInterrupts(); //entry section critical section enableInterrupts(); //exit section reminder section until false; 5/29/2016 COP4610 18 Solution through Disabling Interrupts – cont. 5/29/2016 COP4610 19 Solution through Disabling Interrupts – cont. • This solution may affect the behavior of the I/O system – Interrupts can be disabled for an arbitrarily long time • The interrupts can be disabled permanently if the program contains an infinite loop in its critical section – User programs are not allowed to enable and disable interrupts directly • However, if the operating system can provide system calls, a user can use the system calls for synchronization – Called semaphores and related system calls 5/29/2016 COP4610 20 Software Attempt to Solve the Problem • Only 2 processes, P1 and P2 • General structure of process Pi (other process Pj) repeat entry section critical section exit section reminder section until false; • Processes may share some common variables to synchronize their actions. 5/29/2016 COP4610 21 Algorithm 1 • Shared variables: – var turn: (0..1); initially turn = 0 – turn - i Pi can enter its critical section • Process Pi repeat while turn i do no-op; critical section turn := j; reminder section until false; • Satisfies mutual exclusion, but not progress 5/29/2016 COP4610 22 Algorithm 2 • Shared variables – var flag: array [0..1] of boolean; initially flag [0] = flag [1] = false. – flag [i] = true Pi ready to enter its critical section • Process Pi repeat flag[i] := true; while flag[j] do no-op; critical section flag [i] := false; remainder section until false; • Satisfies mutual exclusion, but not progress requirement. 5/29/2016 COP4610 23 Algorithm 2 – version 1 • Shared variables – var flag: array [0..1] of boolean; initially flag [0] = flag [1] = false. – flag [i] = true Pi ready to enter its critical section • Process Pi repeat while flag[j] do no-op; flag[i] := true; critical section flag [i] := false; remainder section until false; • Does not satisfy mutual exclusion 5/29/2016 COP4610 24 Algorithm 3 • Combined shared variables of algorithms 1 and 2. • Process Pi repeat flag [i] := true; turn := j; while (flag [j] and turn = j) do no-op; critical section flag [i] := false; remainder section until false; • Meets all three requirements; solves the critical-section problem for two processes. 5/29/2016 COP4610 25 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. • The numbering scheme always generates numbers in increasing order of enumeration; i.e., 1,2,3,3,3,3,4,5... 5/29/2016 COP4610 26 Bakery Algorithm – cont. • 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 • Shared data var choosing: array [0..n – 1] of boolean; number: array [0..n – 1] of integer, Data structures are initialized to false and 0 respectively 5/29/2016 COP4610 27 Bakery Algorithm (Cont.) 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; 5/29/2016 COP4610 28 Algorithm 4 • Shared variables: – boolean lock; initially lock = FALSE – lock is FALSE Pi can enter its critical section • Process P1 Process P2 repeat while (lock) do no-op; lock = TRUE; critical section lock = FALSE; reminder section until false; repeat while (lock) do no-op; lock = TRUE; critical section lock = FALSE reminder section until false; 5/29/2016 COP4610 29 Busy Wait Condition shared boolean lock = FALSE; shared double balance; Code for p1 Code for p2 COP4610 Interrupt lock = FALSE Interrupt Interrupt 5/29/2016 lock = TRUE p2 p1 /* Acquire the lock */ while(lock) ; lock = TRUE; /* Execute critical sect */ balance = balance - amount; /* Release lock */ lock = FALSE; Blocked at while /* Acquire the lock */ while(lock) ; lock = TRUE; /* Execute critical sect */ balance = balance + amount; /* Release lock */ lock = FALSE; 30 Synchronization Hardware • Test and modify the content of a word atomically (indivisibly) – The procedure cannot be interrupted until it has completed the routine – Implemented as a test-and-set instruction boolean Test-and-Set (boolean target) { boolean tmp tmp = target; target = true; return tmp; } 5/29/2016 COP4610 31 Test and Set Instruction – cont. • TS(m): [Reg_i = memory[m]; memory[m] = TRUE;] Data CC Register Register R3 … m Data CC Register Register … R3 m FALSE Primary Memory (a) Before Executing TS 5/29/2016 FALSE =0 TRUE Primary Memory (b) After Executing TS COP4610 32 Mutual Exclusion with Test-and-Set • Shared data: boolean lock ; – Initially false • Process Pi repeat while Test-and-Set (lock) do no-op; critical section lock = false; remainder section until false; 5/29/2016 COP4610 33 Semaphores • Semaphore S – integer variable • can only be accessed via two indivisible (atomic) operations – As if they were a single machine instruction wait (S): while S 0 do no-op; S := S – 1; signal (S): S := S + 1; 5/29/2016 COP4610 34 Two 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 using binary semaphores. 5/29/2016 COP4610 35 Example: Critical Section of n Processes • Shared variables – var mutex : semaphore – initially mutex = 1 • Process Pi repeat wait(mutex); critical section signal(mutex); remainder section until false; 5/29/2016 COP4610 36 Shared Account Balance Problem Proc_0() { . . . /* Enter the CS */ P(mutex); balance += amount; V(mutex); . . . } proc_1() { . . . /* Enter the CS */ P(mutex); balance -= amount; V(mutex); . . . } semaphore mutex = 1; fork(proc_0, 0); fork(proc_1, 0); 5/29/2016 COP4610 37 Sharing Two Variables proc_A() { while(TRUE) { <compute section A1>; update(x); /* Signal proc_B */ V(s1); <compute section A2>; /* Wait for proc_B */ P(s2); retrieve(y); } } proc_B() { while(TRUE) { /* Wait for proc_A */ P(s1); retrieve(x); <compute section B1>; update(y); /* Signal proc_A */ V(s2); <compute section B2>; } } semaphore s1 = 0; semaphore s2 = 0; fork(proc_A, 0); fork(proc_B, 0); 5/29/2016 COP4610 38 Bounded Buffer Problem Empty Pool Producer Consumer Full Pool 5/29/2016 COP4610 39 Bounded Buffer Problem – cont. producer() { consumer() { buf_type *next, *here; buf_type *next, *here; while(TRUE) { while(TRUE) { produce_item(next); /* Claim full buffer */ /* Claim an empty */ P(full); P(empty); P(mutex); P(mutex); here = obtain(full); here = obtain(empty); V(mutex); V(mutex); copy_buffer(here, next); copy_buffer(next, here); P(mutex); P(mutex); release(here, emptyPool); release(here, fullPool); V(mutex); V(mutex); /* Signal an empty buffer */ /* Signal a full buffer */ V(empty); V(full); consume_item(next); } } } } semaphore mutex = 1; semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0); 5/29/2016 COP4610 40 Bounded Buffer Problem – cont. producer() { consumer() { buf_type *next, *here; buf_type *next, *here; while(TRUE) { while(TRUE) { produce_item(next); /* Claim full buffer */ /* Claim an empty */ P(full); P(empty); P(mutex); P(mutex); here = obtain(full); here = obtain(empty); V(mutex); V(mutex); copy_buffer(here, next); copy_buffer(next, here); P(mutex); P(mutex); release(here, emptyPool); release(here, fullPool); V(mutex); V(mutex); /* Signal an empty buffer */ /* Signal a full buffer */ V(empty); V(full); consume_item(next); } } } } semaphore mutex = 1; semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0); 5/29/2016 COP4610 41 Bounded Buffer Problem – cont. consumer() { producer() { buf_type *next, *here; buf_type *next, *here; while(TRUE) { while(TRUE) { /* Claim full buffer */ produce_item(next); P(mutex); /* Claim an empty */ P(full); P(empty); here = obtain(full); P(mutex); V(mutex); here = obtain(empty); copy_buffer(here, next); V(mutex); P(mutex); copy_buffer(next, here); release(here, emptyPool); P(mutex); V(mutex); release(here, fullPool); /* Signal an empty buffer */ V(mutex); V(empty); /* Signal a full buffer */ consume_item(next); V(full); } } } } semaphore mutex = 1; semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0); 5/29/2016 COP4610 42 Readers-Writers Problem Writers Readers 5/29/2016 COP4610 43 Readers-Writers Problem (2) Writer Writer Writer Writer Writer Writer Writer Reader Reader Reader Reader Reader Reader Reader Reader Shared Resource 5/29/2016 COP4610 44 Readers-Writers Problem (3) Writer Writer Writer Writer Writer Writer Writer Reader Reader Reader Reader Reader Reader Reader Reader Shared Resource 5/29/2016 COP4610 45 Readers-Writers Problem (4) Reader Reader Reader Reader Reader Reader Reader Reader Writer Writer Writer Writer Writer Writer Writer Shared Resource 5/29/2016 COP4610 46 Readers-writers with active readers 5/29/2016 COP4610 47 First and Second Policy 5/29/2016 COP4610 48 First Solution reader() { writer() { while(TRUE) { while(TRUE) { <other computing>; <other computing>; P(mutex); P(writeBlock); readCount++; /* Critical section */ if(readCount == 1) access(resource); P(writeBlock); V(writeBlock); V(mutex); } /* Critical section */ } access(resource); P(mutex); readCount--; •First reader competes with writers if(readCount == 0) V(writeBlock); •Last reader signals writers V(mutex); } } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); 5/29/2016 COP4610 49 First Solution (2) reader() { while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); P(mutex); readCount--; if(readCount == 0) V(writeBlock); V(mutex); } } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); 5/29/2016 writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } } •First reader competes with writers •Last reader signals writers •Any writer must wait for all readers •Readers can starve writers •“Updates” can be delayed forever •May not be what we want COP4610 50 Writer Precedence reader() { while(TRUE) { <other computing>; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); 4 2 1 access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); 3 V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } } } } int readCount = 0, writeCount = 0; semaphore mutex = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; fork(reader, 0); 5/29/2016 COP4610 51 fork(writer, 0); Writer Precedence (2) reader() { writer() { while(TRUE) { while(TRUE) { <other computing>; <other computing>; P(mutex2); 4 P(writePending); P(readBlock); writeCount++; P(mutex1); if(writeCount == 1) readCount++; P(readBlock); 3 if(readCount == 1) V(mutex2); 2 P(writeBlock); P(writeBlock); V(mutex1); access(resource); V(readBlock); V(writeBlock); 1 V(writePending); P(mutex2) access(resource); writeCount--; P(mutex1); if(writeCount == 0) readCount--; V(readBlock); if(readCount == 0) V(mutex2); V(writeBlock); } V(mutex1); } } } int readCount = 0, writeCount = 0; semaphore mutex = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; fork(reader, 0); 5/29/2016 COP4610 52 fork(writer, 0); The Sleepy Barber • Barber can cut one person’s hair at a time • Other customers wait in a waiting room Entrance to Waiting Room (sliding door) Shop Exit Entrance to Barber’s Room (sliding door) Waiting Room 5/29/2016 COP4610 53 Sleepy Barber customer() { while(TRUE) { customer = nextCustomer(); if(emptyChairs == 0) continue; P(chair); P(mutex); emptyChairs--; takeChair(customer); V(mutex); V(waitingCustomer); } } barber() { while(TRUE) { P(waitingCustomer); P(mutex); emptyChairs++; takeCustomer(); V(mutex); V(chair); } } semaphore mutex = 1, chair = N, waitingCustomer = 0; int emptyChairs = N; fork(customer, 0); fork(barber, 0); 5/29/2016 COP4610 54 Implementing Semaphores • Minimize effect on the I/O system • Processes are only blocked on their own critical sections (not critical sections that they should not care about) • If disabling interrupts, be sure to bound the time they are disabled 5/29/2016 COP4610 55 Implementing Semaphores Using Interrupts class semaphore { int value; public: semaphore(int v = 1) { value = v;}; P(){ disableInterrupts(); while(value == 0) { enableInterrupts(); disableInterrupts(); } value--; enableInterrupts(); }; V(){ disableInterrupts(); value++; enableInterrupts(); }; }; 5/29/2016 COP4610 56 Using the TS Instruction boolean s = FALSE; . . . while(TS(s)) ; <critical section> s = FALSE; . . . 5/29/2016 semaphore s = 1; . . . P(s) ; <critical section> V(s); . . . COP4610 57 Implementing the General Semaphore struct semaphore { int value = <initial value>; boolean mutex = FALSE; boolean hold = TRUE; }; shared struct semaphore s; P(struct semaphore s) { while(TS(s.mutex)) ; s.value--; if(s.value < 0) ( s.mutex = FALSE; while(TS(s.hold)) ; } else s.mutex = FALSE; } 5/29/2016 V(struct semaphore s) { while(TS(s.mutex)) ; s.value++; if(s.value <= 0) ( while(!s.hold) ; s.hold = FALSE; } s.mutex = FALSE; } COP4610 58 Semaphore Implementation – cont. • Semaphores implemented using interrupt disabling and test-and-set require busy waiting – This type of semaphores is often called spinlock 5/29/2016 COP4610 59 Semaphore Implementation – cont. • Define a semaphore as a structure typedef struct { int value; queue L; } semaphore; • Assume two simple operations: – block suspends the process that invokes it. – wakeup(P) resumes the execution of a blocked process P. 5/29/2016 COP4610 60 Semaphore Implementation - cont. • Semaphore operations now defined as P(S): S.value = S.value – 1; if S.value < 0 then begin add this process to S.L; block; end; 5/29/2016 COP4610 61 Semaphore Implementation - cont. V(S): S.value = S.value + 1; if S.value 0 then begin remove a process P from S.L; wakeup(P); end; 5/29/2016 COP4610 62 Semaphore Implementation - cont. • Semaphores are resources in the above implementation 5/29/2016 COP4610 63 Issues Using Semaphores • 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 P(S); P(Q); V(S); V(Q) P1 P(Q); P(S); V(Q); V(S); • Starvation – indefinite blocking – A process may never be removed from the semaphore queue in which it is suspended. 5/29/2016 COP4610 64 Active vs. Passive Semaphores • A process can dominate the semaphore – Performs V operation, but continues to execute – Performs another P operation before releasing the CPU – Called a passive implementation of V • Active implementation calls scheduler as part of the V operation. – Changes semantics of semaphore! – Cause people to rethink solutions 5/29/2016 COP4610 65 Summary • Processes that share data need to be synchronized – Otherwise, a race condition may exist • Semaphores are the basic mechanism underlying synchronization and can be used to solve different synchronization problems – Critical section problem – Bounded-buffer problem – Readers-writers problem 5/29/2016 COP4610 66