280 likes | 283 Views
Synchronization II:. CPE 261403 - Operating Systems http://www.e-cpe.org/moodle. Classical Problems of Synchronization. Bounded-Buffer Problem (6.6.1) Dining-Philosophers Problem (6.6.3) (Readers-Writers Problem 6.6.2). How many orders does Amazon.com receives per day?. Peak day for 2008
E N D
Synchronization II: CPE 261403 - Operating Systems http://www.e-cpe.org/moodle
Classical Problems of Synchronization • Bounded-Buffer Problem (6.6.1) • Dining-Philosophers Problem (6.6.3) • (Readers-Writers Problem 6.6.2)
How many orders does Amazon.com receives per day? Peak day for 2008 6.3M orders in one day ( = 72.9 orders per sec)
Order Order Order Order Order Process & Ship Process & Ship Process & Ship Process & Ship Process & Ship
Bounded-Buffer Problem Produce(Data) { // produce an item if (bufferLen < N) { Buffer[bufferLen] = Data bufferLen++; } } Consume() { // consume an item if (bufferLen > 0) { return Buffer[bufferLen--]; } } Consumer Producer What is the problem with this code?
Bounded-Buffer Problem 1 0 N Semaphores Mutex Full Empty while (true) { // produce an item wait (empty); wait (mutex); // add the item to the buffer signal (mutex); signal (full); } while (true) { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } Consumer Producer
Example of a simple human error 1 0 N Semaphores Mutex Full Empty while (true) { // produce an item wait (empty); wait (mutex); // add the item to the buffer if (error) { exit(0); } signal (mutex); signal (full); } while (true) { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } Semaphore not properly set before exit Consumer Producer
Correcting the error 1 0 N Semaphores Mutex Full Empty while (true) { // produce an item wait (empty); wait (mutex); // add the item to the buffer if (error) { signal (mutex); signal (empty); exit(0); } signal (mutex); signal (full); } while (true) { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } Reset semaphores before exiting Consumer Producer
Example II of a simple human error 1 0 N Semaphores Mutex Full Empty while (true) { // produce an item wait (empty); wait (mutex); // add the item to the buffer if (error) { signal (mutex); signal (empty); if (just-a-warning) { warn-user; } if (critical Error) {exit(0); } } signal (mutex); signal (full); } while (true) { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } Producer and Consumer can become “Out of sync” because “Signal” may be run twice Consumer Producer
Correcting the error 1 0 N Semaphores Mutex Full Empty while (true) { // produce an item wait (empty); wait (mutex); // add the item to the buffer if (error) { if (just-a-warning) { warn-user; } if (critical Error) { signal (mutex); signal (empty); exit(0); } } signal (mutex); signal (full); } while (true) { wait (full); wait (mutex); // remove an item from buffer signal (mutex); signal (empty); // consume the removed item } Putting ‘signal’ in the right condition Consumer Producer
Monitors • Higher level API than Semaphores • Can help prevent human error Figure 6.19
Bounded Buffer Problem • monitorBoundedBuffer { • functionProduce (value) { • if BufferLen < N • // Add a value to Buffer • BufferLen++; • } • Function consume() { • If BufferLen > 0 • // remove a value from Buffer • BufferLen--; • } • } • // usage example • BoundedBuffer.Produce(x) • Output = BoundedBuffer.Consume() Functions in a Monitor is mutual exclusive by default Can use a simple variable instead of a counting semaphore
Using “Conditions” to Sync Threads • monitorBoundedBuffer { • Condition content • Condition emptySpace • functionProduce (value) { • if BufferLen < N • // Add a value to Buffer • content.signal() • else • emptySpace.wait() • // Add a value to Buffer • } • Function consume() { • If BufferLen > 0 • // remove a value from Buffer • emptySpace.signal() • else • content.wait() • // remove a value from Buffer • } • } Wait conditions put the thread to sleep and releases the monitor to other threads. A “signal” wakes the thread.
“Condition” properties • Condition.Wait() puts the process to sleep. • Condition.signal() wakes up exactly one process. If no process is waiting, then signal has no effect.
Dining-Philosophers Problem Figure 6.16
A solution using SemaphoresEvery philosopher runs this code While (true) { wait ( chopstick[i] ); wait ( chopStick[ (i + 1) % 5] ); // eat signal ( chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // think }
Using Monitors monitor DP { enum { THINKING; HUNGRY, EATING) state [5] ; condition self [5]; void pickup (int i) { state[i] = HUNGRY; test(i); if (state[i] != EATING) self [i].wait; } void putdown (int i) { state[i] = THINKING; // test left and right neighbors test((i + 4) % 5); test((i + 1) % 5); }
Using Monitors (Cont.) void test (int i) { if ( (state[(i + 4) % 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) % 5] != EATING) ) { state[i] = EATING ; self[i].signal () ; } } initialization_code() { for (int i = 0; i < 5; i++) state[i] = THINKING; } }
Readers Writers Problem (I) Readers Writers Writers Readers Writers Writers Readers Readers One at a time Concurrent Read DATA • Writers will wait for all readers to finish • Readers cannot read only when a writer is already running
Semaphore Thread writer() { While (true) { Wait (wrt);// รอจนกว่าจะได้ semaphore wrt จึงจะเข้าไปเขียนข้อมูล // ทำการเขียนข้อมูลที่นี่ Signal (wrt); } }
Thread reader() { While (true) { Wait (mutex); // ร้องขอ mutex เพราะมีการแปลงค่าตัวแปร readcount ถือเป็น critical section Readcount++; // นับว่ามี reader ทำงานอยู่กี่ตัว If (readcount == 1)// reader ที่เข้ามาตัวแรกจะยึด semaphore wrt ไว้ไม่ให้ writer ทำงาน Wait (wrt); Signal (mutex); // ทำการอ่านข้อมูลที่นี่ Wait (mutex);// มีการแปลงค่าตัวแปร ถือเป็น critical section เช่นเดียวกับข้างต้น Readcount--;// ลดจำนวนนับ reader ลง If (readcount == 0)// ถ้าไม่เหลือ reader แล้วก็ปล่อย semaphore wrt เพื่อให้ writer ทำงานได้ Signal (wrt); Signal(mutex); } }
Using Monitors • Monitor RWProblem { • Void Read() { • // อ่านข้อมูล • } • Void Write() { • // เขียนข้อมูล • } • } Does this work? No. Because (1) No more than one reader can run at a time (2) We cannot control our policy (readers before writers)
Monitor RWProblem { • int readcount=0; // ใช้นับว่ามี reader กี่ตัว • boolean busy = 0; • condition okToWrite; • condition okToRead; • void StartWrite() { • if ((readcount > 0) || (busy==1)) { okToWrite.wait() } • busy = 1; • } • Void EndWrite () { • busy = 0; • if okToRead.QueueCount > 0 { okToRead.signal(); } • else { okToWrite.signal(); } • } • void StartRead() { • if (busy) { okToRead.wait(); } • readcount++; // นับว่ามี reader ทำงานอยู่กี่ตัว • okToRead.signal();// ถ้า reader ได้ทำงานตัวหนึ่งแล้วตัวอื่นที่ wait อยู่ก็จะได้ทำงานด้วย • } • Void EndRead() { • readcount--; • If (readcount == 0){ okToWrite.signal();} • } • }