consumer trouble
play

Consumer Trouble! item i; /* item consumed */ P: R1 = counter - PDF document

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


  1. 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. (Ch 4.4-4.6, 7.1-7.7) 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

  2. Consumer Trouble! item i; /* item consumed */ P: R1 = counter {R1 = 5} int out; /* take next item */ P: R1 = R1 + 1 {R1 = 6} while (1) { C: R2 = counter {R2 = 5} while (counter == 0) {/*no-op*/} C: R2 = R2 -1 {R2 = 4} item = buffer[out]; C: counter = R2 {counter = 4} out = (out + 1) % MAX; counter = counter - 1; P: counter = R1 {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) • Note, no assumptions about speed! /* remainder section */ } Second Try Third Try: Peterson’s Solution int flag[1]; /* boolean */ int flag[1]; /* boolean */ int turn; while(1) { while(1) { flag[my_pid] = true; flag[my_pid] = true; turn = your_pid; while (flag[your_pid]) { /* no-op */} while (flag[your_pid] && /* critical section */ turn==your_pid){ /* noop */} flag[my_pid] = false; /* critical section */ /* remainder section */ flag[my_pid] = false; } /* remainder section */ } 2

  3. Multiple-Processes Multiple-Processes choosing[my_pid] = true; num[my_pid] = max(num[0],num[1] …)+1 • “Bakery Algorithm” choosing[my_pid] = false; • Common data structures for (j=0; j<n; j++) { boolean choosing[n]; while(choosing[j]) { } int num[n]; while(num[j]!=0 && • Ordering of processes (num[j],j)<(num[my_pid],my_pid)){} } – If same number, can decide “winner” /* critical section */ num[my_pid] = 0; Synchronization Hardware Using Test_and_Set • Test-and-Set: returns and modifies atomically while(1) { while (Test_and_Set(lock)) { } int Test_and_Set(int &target) { /* critical section */ int temp; lock = false; temp = target; /* remainder section */ target = true; } return temp; } • All the solutions so far have required “Busy Waiting” … what is that? Outline Semaphores • Need for synchronization • Do not require “busy waiting” (done) • Semaphore S (shared, often initially =1) – why? • Solutions that require busy waiting (done) – integer variable – what? – accessed via two (indivisible) atomic operations • Semaphores wait(S): S = S - 1 – what are they? • Classical problems if S<0 then block(S) signal(S): S = S + 1 – dining philosophers – reader/writers if S<=0 then wakeup(S) 3

  4. Critical Section w/Semaphores Semaphore Implementation semaphore mutex; /* shared */ • Disable interrupts – Why is this not evil? while(1) { – Multi-processors? wait(mutex); • Use correct software solution /* critical section */ • Use special hardware, i.e.- Test-and-Set signal(mutex); /* remainder section */ } (Hey, you! Show demo!) 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 – name servers, on-line help wait(S) wait(Q) wait(Q) wait(S) … … Classical Synchronization Dining Philosophers Problems • Bounded Buffer • Philosophers • Readers Writers – Think – Sit • Dining Philosophers – Eat – Think • Need 2 chopsticks to eat 4

  5. Dining Philosophers Other Solutions Philosopher i: • Allow at most N-1 to sit at a time while (1) { • Allow to pick up chopsticks only if both are /* think… */ wait(chopstick[i]); available • Asymmetric solution (odd L-R, even R-L) wait(chopstick[i+1 % 5]); /* eat */ signal(chopstick[i]); signal(chopstick[i+1 % 5]); } (Other solutions?) Readers-Writers Readers-Writers Shared: semaphore mutex, wrt; • Readers only read the content of object int readcount; • Writers read and write the object • Critical region: Writer: – No processes wait(wrt) – One or more readers (no writers) /* write stuff */ – One writer (nothing else) • Solutions favor Reader or Writer signal(wrt); Readers-Writers Monitors Reader: • High-level construct wait(mutex); • Collection of: readcount = readcount + 1; – variables if (readcount==1) wait(wrt); – data structures signal(mutex); – functions – Like C++ class /* read stuff */ • One process active inside wait(mutex); • “Condition” variable readcount = readcount - 1; – not counters like semaphores if (readcount==0) signal(wrt); signal(mutex); 5

  6. Monitor Producer-Consumer Monitor Producer-Consumer void producer() { item i; monitor ProducerConsumer { while (1) { condition full, empty; /* produce item i */ integer count; ProducerConsumer.enter(i); } /* function prototypes */ } void enter(item i); void consumer() { item remove(); item i; } while (1) { void producer(); i = ProducerConsumer.remove(); void consumer(); /* consume item i */ } } Other Process Synchronization Monitor Producer-Consumer Methods void enter (item i) { if (count == N) sleep(full); • Sequencers /* add item i */ • Path Expressions count = count + 1; • Serializers if (count == 1) then wakeup(empty); } • ... item remove () { • All essentially equivalent in terms of if (count == 0) then sleep(empty); /* remove item into i */ semantics. Can build each other! count = count - 1; if (count == N-1) then wakeup(full); return i; } 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 • In general, Inter-Process Communication – pipes - unidirectional stream communication (IPC) – message passing - processes send and receive – Move towards Message Passing messages. 6

  7. Pipes The Pipe • One process writes, 2nd process reads % ls | more 1 \0 b l a h . c Shell 2 3 ls more read fd write fd stdout stdin • Shell: • Bounded Buffer 1 create a pipe – shared buffer (Unix 4096K) 2 create a process for ls command, setting – block writes to full pipe stdout to write side of pipe – block reads to empty pipe 3 create a process for more command, setting stdin to read side of pipe (Hey, see sample code!) The Pipe Message Passing • Process inherits file descriptors from parent • Communicate information from one process – file descriptor 0 stdin, 1 stdout, 2 stderr • Process doesn't know (or care!) when reading to another via primitives: from keyboard, file, or process or writing to send(dest, &message) terminal, file, or process receive(source, &message) • System calls: • Receiver can specify ANY – read(fd, buffer, nbytes) ( scanf() built on top) • Receiver can block (or not) – write(fd, buffer, nbytes) ( printf() built on top) – pipe(rgfd) creates a pipe + rgfd array of 2 fd. Read from rgfd[0], write to rgfd[1] • (Hey, show sample code!) Producer-Consumer Consumer Mailbox void Producer() { while (TRUE) { /* produce item */ void Consumer { build_message(&m, item); for (i=0; i<N; i++) send(consumer, &m); send(producer, &m); /* N empties */ receive(consumer, &m); /* wait for ack */ while(1) { }} receive(producer, &m); void Consumer { extract_item(&m, &item); while(1) { send(producer, &m); /* ack */ receive(producer, &m); /* consume item */ “Rendezvous” extract_item(&m, &item); } send(producer, &m); /* ack */ } /* consume item */ }} 7

Recommend


More recommend