Too Much Pizza Person A Person B 3:00 Look in fridge. Pizza! 3:05 Leave for store. Look in fridge. Pizza! 3:10 Arrive at store. Leave for store. Operating Systems 3:15 Buy pizza. Arrive at store. 3:20 Arrive home. Buy pizza. 3:25 Put away pizza. Arrive home. Process Synchronization 3:30 Put pizza away. Oh no! Cooperating Processes Outline • Consider: print spooler • Need for synchronization – Enter file name in spooler queue – why? • Solutions that require busy waiting – Printer daemon checks queue and prints – what? • Semaphores A B free 9 – what are they? • Classical problems letter hw1 lab1.c (empty) ... ... – dining philosophers 6 7 8 9 – reader/writers � “Race conditions” (ugh!) � (Hey, you! Show demo!) Producer Consumer Producer item i; /* item produced */ • Model for cooperating processes int in; /* put next item */ • Producer “produces” and item that while (1) { consumer “consumes” produce an item • Bounded buffer (shared memory) while (counter == MAX){/*no-op*/} item buffer[MAX]; /* queue */ buffer[in] = item; int counter; /* num items */ in = (in + 1) % MAX; counter = counter + 1; } 1
Consumer Trouble! item i; /* item consumed */ R1 = counter {R1 = 5} int out; /* take next item */ P: R1 = R1 + 1 P: {R1 = 6} while (1) { R2 = counter {R2 = 5} while (counter == 0) {/*no-op*/} C: R2 = R2 -1 item = buffer[out]; C: {R2 = 4} counter = R2 out = (out + 1) % MAX; {counter = 4} C: counter = counter - 1; counter = R1 P: {counter = 6} consume the item } Critical Section First Try: Strict Alternation • Mutual Exclusion int turn; /* shared, id of turn */ – Only one process inside critical region • Progress while(1) { – No process outside critical region may block other while (turn <> my_pid) { /* no-op */} processes wanting in /* critical section */ • Bounded Waiting turn = your_pid – No process should have to wait forever (starvation) /* remainder section */ • Note, no assumptions about speed! } Second Try Questions int flag[1]; /* boolean */ • How does Windows NT avoid process while(1) { starvation? • What is a “race condition”? flag[my_pid] = true; while (flag[your_pid]) { /* no-op */} • What are 3 properties necessary for a /* critical section */ correct “critical region” solution? flag[my_pid] = false; /* remainder section */ } 2
Third Try: Peterson’s Solution Multiple-Processes int flag[1]; /* boolean */ int turn; • “Bakery Algorithm” while(1) { • Common data structures flag[my_pid] = true; boolean choosing[n]; turn = your_pid; int num[n]; while (flag[your_pid] && turn==your_pid){ /* noop */} • Ordering of processes /* critical section */ – If same number, can decide “winner” flag[my_pid] = false; /* remainder section */ } Multiple-Processes Synchronization Hardware choosing[my_pid] = true; • Test-and-Set: returns and modifies atomically num[my_pid] = max(num[0],num[1] …)+1 choosing[my_pid] = false; int Test_and_Set(int &target) { for (j=0; j<n; j++) { int temp; while(choosing[j]) { } while(num[j]!=0 && temp = target; (num[j],j)<(num[my_pid],my_pid)){} target = true; } return temp; /* critical section */ } num[my_pid] = 0; Using Test_and_Set Outline while(1) { • Need for synchronization while (Test_and_Set(lock)) { } – why? • Solutions that require busy waiting /* critical section */ – what? lock = false; • Semaphores /* remainder section */ – what are they? • Classical problems } – dining philosophers – reader/writers • All the solutions so far have required “Busy Waiting” … what is that? 3
Critical Section w/Semaphores Semaphores semaphore mutex; /* shared */ • Do not require “busy waiting” • Semaphore S (shared, often initially =1) while(1) { – integer variable wait(mutex); – accessed via two (indivisible) atomic operations /* critical section */ wait(S): S = S - 1 if S<0 then block(S) signal(mutex); signal(S): S = S + 1 /* remainder section */ if S<=0 then wakeup(S) } (Hey, you! Show demo!) SOS: Semaphore Implementation Semaphore Implementation • Disable interrupts • Note: key and int are different – Why is this not evil? – Like share-sem.c sample – Multi-processors? • How do you make sure the signal and the • Use correct software solution wait operations are atomic? • Use special hardware, i.e.- Test-and-Set Design Technique: Reducing a Trouble! Problem to a Special Case signal(S) wait(S) • Simple solution not adequate /* cr */ /* cr */ – ex: disabling interrupts wait(S) wait(S) • Problem solution requires special case solution /* cr */ – ex: protecting S for semaphores • Simple solution adequate for special case • Other examples: Process A Process B wait(S) wait(Q) – name servers, on-line help wait(Q) wait(S) … … 4
Classical Synchronization Dining Philosophers Problems • Bounded Buffer • Philosophers • Readers Writers – Think – Sit • Dining Philosophers – Eat – Think • Need 2 chopsticks to eat Dining Philosophers Philosopher i: while (1) { /* think… */ Other Solutions? wait(chopstick[i]); wait(chopstick[i+1 % 5]); /* eat */ signal(chopstick[i]); signal(chopstick[i+1 % 5]); } Other Solutions Readers-Writers • Allow at most N-1 to sit at a time • Readers only read the content of object • Allow to pick up chopsticks only if both are • Writers read and write the object • Critical region: available • Asymmetric solution (odd L-R, even R-L) – No processes – One or more readers (no writers) – One writer (nothing else) • Solutions favor Reader or Writer 5
Readers-Writers Readers-Writers Shared: Reader: semaphore mutex, wrt; wait(mutex); int readcount; readcount = readcount + 1; if (readcount==1) wait(wrt); signal(mutex); Writer: wait(wrt) /* read stuff */ /* write stuff */ wait(mutex); signal(wrt); readcount = readcount - 1; if (readcount==0) signal(wrt); signal(mutex); Monitors Monitor Producer-Consumer • High-level construct monitor ProducerConsumer { • Collection of: condition full, empty; integer count; – variables – data structures /* function prototypes */ – functions void enter(item i); – Like C++ class item remove(); • One process active inside } • “Condition” variable void producer(); – not counters like semaphores void consumer(); Monitor Producer-Consumer Monitor Producer-Consumer void producer() { void enter (item i) { item i; if (count == N) wait(full); while (1) { /* add item i */ /* produce item i */ count = count + 1; ProducerConsumer.enter(i); if (count == 1) then signal(empty); } } } item remove () { void consumer() { if (count == 0) then wait(empty); item i; /* remove item into i */ while (1) { count = count - 1; i = ProducerConsumer.remove(); if (count == N-1) then signal(full); /* consume item i */ return i; } } } 6
Other Process Synchronization Ex: Cond. Crit. Region w/Sem region X when B do S { Methods wait(x-mutex); • Critical Regions if (!B) { • Conditional Critical Regions x-count = x-count + 1; • Sequencers signal(x-mutex); • Path Expressions wait(x-delay); • Serializers /* wakeup loop */ • ... x-count = x-count -1 • All essentially equivalent in terms of semantics. } Can build each other! /* remainder */ Ex: Wakeup Loop Ex: Remainder while (!B) { S; x-temp = x-temp + 1; if (x-temp < x-count) if (x-count > 0) { signal(x-delay); x-temp = 0; else signal(x-delay); signal(x-mutex); } else wait(x-delay); signal(x-mutex); } Trouble? Inter Process Communication • Monitors and Regions attractive, but ... • How does one process communicate with another process? Some of the ways: – Not supported by C, C++, Pascal ... + semaphores easy to add – shared memory – read/write to shared region • Monitors, Semaphores, Regions ... + shmget(), shmctl() in Unix + Memory mapped files in WinNT/2000 – require shared memory – semaphores -- signal notifies waiting process – break on multiple CPU (w/own mem) – software interrupts -- process notified – break distributed systems asynchronously • Move towards Message Passing – pipes -- unidirectional stream communication – message passing -- processes send and receive messages. 7
Recommend
More recommend