Presentation is loading. Please wait.

Presentation is loading. Please wait.

Process Synchronization: Conclusion

Similar presentations


Presentation on theme: "Process Synchronization: Conclusion"— Presentation transcript:

1 Process Synchronization: Conclusion
COS 431

2 Event Counters Alternative producer/consumer solution
No need for mutex semaphore Example events: Adding/removing item Idea: count events Processes wait for some number of events Atomicity: requires kernel support Kernel support: for advancing event counter, to wait for some value

3 Event Counter Example void consumer () { int item, num_items = 0;
while (TRUE) { num_items++; /* wait till buffer holds more items than we’d like to consume */ await(in,num_items); item = remove_item(buffer); advance(&out); consume_item(item); } typedef int event_counter; event_counter in = 0; event_counter out = 0; void producer() { int item, num_items = 0; while (TRUE) { item = produce(); num_items++; /* wait for num out >= (num produced - buffer size) -- that is, until there’s room in the buffer */ await(out,num_items - NUM_SLOTS); enter_item(item,buffer); advance(&in); /* tell consumer something has arrived */ } Event counters: await(i,j) blocks unless i>=j advance is atomic Will this work with more than 2 processes? not as written (local counters) how to fix? can it be fixed? (maybe use in, out instead of local counters? – if await goes back to old version of blocking unless I>j, not I>=j)

4 Programming Language Support
Problems: Cheating Bugs Solution: programming language support for critical region Region construct region var when cond do stmt; var buffer: shared record... end; /* consumer */ region buffer when count < n do begin /* add to buffer */ end; /* consumer */ region buffer when count > 0 do begin /* take from buffer */ end; Programming language support some programming languages provide direct support for process synchronization region stmt only executed if “COND” is true -- if not true, then process waits until it is and no other process is within critical region

5 Monitors Monitor: programming language construct for process synch.
Object-like semantics: procedures and variables are inside of monitors Only one process can be active within a monitor at any given time Cheating: this can happen even with “region” construct; as can sloppiness Monitor: programming language construct that enforces mutual exclusion and helps prevent deadlocks - compiler might implement this with mutex semaphore and inserting calls to down/up in the code

6 Example monitor COS431; integer students[0..MAX]; last := 0;
procedure register(student); end; procedure drop(student); What’s missing here? -- can drop non-existent student! How to fix? have drop wait on a new condition variable if last = 0

7 Potential problem: suppose we have bounded buffer problem
need mutex... ...but also need way for process to wait until buffer is not full/empty yet if do this inside of monitor (naively), then deadlock

8 Solution: Condition Variables
Condition variables used for interprocess communication Process can’t proceed => wait on a condition => not “active” Allows another process to enter monitor When resource free, active process uses signal on condition variable Original process awakens Monitors have condition variables that allow communication between processes When process can’t proceed, it waits on a condition variable associated with the reason Waiting on a condition variable -- allows other proceses to enter the monitor -- first process is no longer “active” When second process finishes and condition is no longer true -- e.g., a resource has been freed -- then it calls signal on the condition variable to awaken the sleeper

9 Monitor Condition Variables
Possible problem: both signaler and ex-sleeper active simultaneously! Solution: make process that signaled exit immediately from the monitor Can we do this?? If several processes are waiting on a condition variable, pick one Problem with condition variables: they aren’t counters ==> can’t buffer “signals” like a semaphore does -- signals can be lost solution: use state variables for each process if P1 wants to signal P2, but P2 not waiting - don’t signal Can’t get deadlock with monitors -- sleep and wakeup done only within monitor, and only one active process allowed at a time What if other process forgets to signal? Solution: can we do this? Yes! Compiler has control

10 Example of Monitors: Bounded Buffer
monitor COS431; integer students[0..MAX]; condition full; last := 0; procedure register(student); if last = MAX then wait(full); last := last + 1; students[last] := student; end; procedure drop(student); remove(student,students); last := last - 1; signal(full); P1: COS431.register(“Paul”); ...last now equals max... COS431.register(“Mary”); ==> blocks P2: COS431.drop(“Jim”); ...P1 wakes up, finishes adding What’s missing here? -- can drop non-existant student! How to fix? have drop wait on a new condition variable if last = 0

11 Problem with Monitors Requires programming language support
C, Pascal, C++, Java – don’t have this Concurrent Euclid does, but... Same problems for regions

12 Problems with Synchronization Mechanisms
Semaphores: low-level cheating don’t work without shared memory--e.g., when processes are on different machines Signals: only boolean information can be passed only on same machine Monitors: need programming language support what if don’t have that language, or need multiple languages?

13 Message Passing New abstraction/metaphor: process sends a message...
...another receives it later Same or different machines System calls -- e.g.: send(dest,&msg); receive(dest,&msg); Not what they’re called in Unix (mq_send, e.g.) Blocking: blocking receives blocking or non-blocking sends

14 Solving the Registrar Problem with Messages
Registrar Server void main() { while (TRUE) { receive(source,&msg); parse(msg); if (full(class)) { send(source, “sorry”); } else { add(student,class); send(source, “okay”); } Client Program void add(student,class) { create_msg(&msg,student,class); send(registrar,&msg); receive(registrar,&msg); report_results(&msg); } What if there are no students? What if class full?

15 Producer/Consumer with Messages
void main() { // use messages instead of buffer for (i = 0; i < MAX; i++) { send(producer,&msg); } while (TRUE) { receive(producer,&msg); item = extract_item(&msg); // send back “empty” process_item(item); Producer void main() { while (TRUE) { produce(&item); receive(consumer,&msg); pack(item,&msg); send(consumer,&msg); } Instead of a buffer, message “empties” are used messages have to be buffered somewhere -- in the kernel so what happens if we hit the max buffer size in the kernel?

16 Producer/Consumer Receiving from Anyone
lpr Program, Machine A void main(int ARGC, char *ARGV[]) { process_args(&filename); pack(&msg,filename); send(lpd, &msg); // wait for reply receive(lpd,&msg); } lpd Daemon, Machine B void main() { while (TRUE) { receive(&any,&msg); unpack(&msg,&filename); send(any,&msg); print_file(filename); } This isn’t how lpr/lpd work, of course!! What are some possible problems? lpd is slower than lpr’s, or there are many of them => message queue on lpd machine is full would have to hope network was able to make sender block until message queue has slot on receiver Do we need the receive on the lpr side? not really, unless we want status information -- in this case, we will allow the send to block if the message queue is full, so we’re not communicating using a virtual buffer of message “empties”

17 Message Passing Messages -- usually buffered until needed in kernel
Can implement such that sends block rendezvous: synchronize two processes Problems when processes on different machines: Lost messages acknowledge messages ack lost: timeout, retransmit receiver must be able to handle redundant, out-of-order msgs Addressing same machines: PIDs unique different machines: hostname, PIDs may not be unique use PID + Internet address: Rendezvous: proc A: send(B,&msg); receive(B, &msg); proc B: send(A,&msg); receive(A, &msg);

18 Equivalence of Primitives
Can implement one kind of synchronization primitive with another E.g.: implement monitors with semaphores Need mutex -- govern access to monitor Need semaphore for each condition variable Compiler help: insert proper system calls where enter/exit monitor Process 1 enter_monitor: Down(mutex); work (in monitor) work exit_monitor: Up(mutex); work (out of monitor) enter_monitor: Down(mutex); blocked wake up, work in monitor exit_signal(cvar1): Up(cvar1); Process 2 enter_monitor: Down(mutex) wake up, enter monitor wait(cvar1): Up(mutex),Down(cvar1) wake up exit_monitor: Up(mutex) What should condition semaphore be set to? so first wait() will block (the processes check condition variables to avoid wrong calls on this) could also rewrite to use counting vars ...but if we’re the compiler writer, we couldn’t -- don’t know what user is doing with its counter! What about the end - proc. 1 seems like it should have used an Up(mutex)! But here’s the sequence: 1: Down(mutex) --> mutex = 0 2: Down(mutex) => mutex=-1 (p2 waiting) 1: Up(mutex) => mutex = 0, 2 in monitor 2: Down(mutex) => mutex = -1, p1 waiting 2: Up(mutex) => mutex = 0, p2 in monitor; Down(cvar1) => p1 waits 1: Up(cvar1) => cvar = 0, p2 wakes up in monitor, mutex remains at 0 (p2 in critical region) -- p1 must exit the monitor now!!

19 Semaphores Implemented via Messages
E.g., for distributed process synchronization Need a synchronization process Down(s) { put specifier for Down, s in msg; send(syncProc,&msg); receive(syncProc,&msg); } Up(s) { put specifier for Up, syncProc() { semaphore semArray[N]; receive(&any,&msg); parse into Up/Down, s; if (Up) { semArray[s].count++; if (processes waiting on s) { remove process p from queue; send(p,&msg); send(&any,&msg); } else { semArray[s].count--; if (semaphore[s].count < 0) { put s on queue; /* implicit block - no msg */ send(&any,msg);

20 Classical Problems: Dining Philosophers
Five philosophers Two states: eating or thinking Fork between each pair Each needs two forks to eat (spaghetti, say; or chopsticks rather than forks) Problem: assure no deadlocks, no starvation

21 Dining Philosophers: Simple “Solution”
Use one semaphore per fork while (TRUE) { think(); Down(left_fork); Down(right_fork); eat(); Up(right_fork); Up(left_fork); } problem: Suppose all take right (or left) fork simultaneously -- deadlock What if we modify to allow checking to see if fork busy before down? => still potential deadlock, with bad luck in timing Could use mutex -- Down before eat, Up afterward would solve problem, but not efficiently only one philosopher could eat at once Problem? Can we check fork first? Can we use mutex semaphore?

22 Dining Philosophers: Solution
Use state array (eating, thinking, hungry) Also semaphore per philosopher Philosopher’s semaphore set to 0 initially void main() { while (TRUE) { think(); take_forks(i); eat(); // eating put_forks(i); } take_forks(i) { Down(mutex); state[i] = HUNGRY; test(i); // forks free? Up(mutex); Down(semaphore[i]); test(i) { if ((state[i] == HUNGRY) && (state[right(i)] != EATING) && (state[left(i)] != EATING)) { state[i] = EATING; Up(semaphore[i]); } put_forks(i) { Down(mutex); state[i] = THINKING; test(left(i)); test(right(i)); Up(mutex); Relying on test(I) to determine if philosopher(I) can eat or not via semaphore Test also enables neighbors to eat when called from put_forks()

23 Readers/Writers Often: multiple readers multiple writers
ex: databases, ATMs, etc. Any problem with: multiple readers? multiple writers? readers & writers simultaneously? How to synchronize, so that: readers and writers respect shared data and maximum utilization of shared resource? Solution uses two semaphores, mutex and wrt examples: files, array entries, database entries

24 Readers/Writers: Solution?
Down(mutex); Down(wrt); ...write... Up(wrt); Up(mutex); end; reader: Down(mutex); readers++; if (readers == 1) Down(wrt); Up(mutex); ...read... readers--; if (readers == 0) Up(wrt); end; NOT A SOLUTION!! if writer is waiting on wrt, readers are locked out, as are other writers this would happen when reader is in crit reg, does down on wrt during “...read...”, if writer comes in, it’ll block on wrt then reader will immediately block on mutex => deadlock Idea was:- writer waits on mutex until nothing else dealing with data - reader blocks only momentarily on mutex -- this is how multiple ones can read -- but will cause writer to block on wrt semaphore if it's the first reader - last reader out do Up on wrt to free up/allow in any writer

25 A Readers/Writers Solution
void reader() { while (TRUE) { down(mutex); rc++; // reader count if (rc == 1) down(wrt); up(mutex); ...read data... rc--; if (rc == 0) up(wrt); ...use data... } void writer () { while (TRUE) { ...produce data... down(wrt); ...write data... up(wrt); } Writer doesn’t use mutex -- wrt is serving as mutex for it with respect to other writers First reader blocks writers what if writer comes while reader is in mutex and before it does the down on wrt? -- reader blocks, writer continues last reader out ups wrt to allow writing This solution: gives priority to readers even if writer is waiting, new readers can enter could starve the writer Other solutions have been devised to prevent writer starvation block new readers until writer is done problem: not as parallel as they could be Maybe not any really good solutions that satisfies every criterion.


Download ppt "Process Synchronization: Conclusion"

Similar presentations


Ads by Google