Value Queue “acquire” op “release” op “broadcast” or “release all” op Lock 0/1 ? Lock Unlock No Block till value = 0; Value = 0 set value = 1 8: Classic Synchronization Semaphore INT Y Wait Signal No? value — Value++ While (getValue()<0){ Problems and Deadlock If value < 0 If value <=0 Signal Add self to queue Wake up one } Condition N/A Y Wait Signal Easy to variable Put self on queue If process on Support Last Modified: queue, wake up A signal all 6/14/2004 11:54:49 AM one Event 0/1 Y Wait Signal Default signal does If Value = 0, put Value = 1 self on queue Wake up all Monitor 0/1 Y Call proc in monitor Return from proc No in monitor -1 -2 Bounded Buffer Classical Synchronization Problems Producer/Consumer r Bounded-Buffer Problem r Finite size buffer (array) in memory shared by (also called Producer-Consumer) multiple processes/threads r Producer threads “produce” an item and place in in the buffer r Readers and Writers Problem r Consumer threads remove an item from the buffer and “consume” it r Why do we need synchronization? r Dining-Philosophers Problem m Shared data = the buffer state m Which parts of buffer are free? Which filled? r What can go wrong? m Producer doesn’t stop when no free spaces; Consumer tries to consume an empty space; Consumer tries to consume a space that is only half-filled by the producer; Two producers try to produce into same space; Two -3 consumers try to consume the same space,… -4 Monitor Solution to Bounded- Monitor Solution to Bounded- Buffer Buffer container_t { //monitor boundedBuffer cont void consumer (){ BOOL free = TRUE; while( allBuffersEmpty()){ void producer (){ item_t item; wait(notAllEmpty) while( allBuffersFull()){ } } wait(notAllFull ) monitor boundedBuffer { } which = findFullBuffer (); conditionVariable notAllFull; consumeItem(which->item); conditionVariable notAllEmpty; which = findFreeBuffer (); which->free = TRUE; container_t buffer[FIXED_SIZE]; which->free = FALSE; numFull--; int numFull = 0; which->item = produceItem(); numFull++ signal(notAllFull); } signal(notAllEmpty ); } } //end Monitor -5 -6 1 Semaphore Solution to Semaphore Solution to Bounded-Buffer Bounded-Buffer semaphore_t mutex; void producer (){ void consumer (){ semaphore_t full; container_t *which; container_t *which; semaphore_t empty; wait(empty); wait(full); wait ( mutex); wait ( mutex); container_t { BOOL free = TRUE; which = findFreeBuffer (); item_t item; which = findFullBuffer (); which->free = FALSE; } consumeItem(which->item); container_t which->item = produceItem(); which->free = TRUE; buffer[FIXED_SIZE]; signal (mutex); signal (mutex); void initBoundedBuffer { signal (full); signal (empty); mutex.value = 1; } } full.value = 0; empty.value = FIXED_SIZE •Can we do better? Lock held while produce/consume? } -7 -8 Semaphore Solution to Readers/ Readers/writers Writers (Reader Preference) semaphore_t mutex; r Shared data area being accessed by multiple void reader (){ semaphore_t okToWrite; processes/threads int numReaders ; wait(mutex ); numReaders ++; r Reader threads look but don’t touch void init{ if (numReaders ==1) m We can allow multiple readers at a time. Why? mutex.value = 1; wait(okToWrite); //not ok to write r Writer threads touch too. okToWrite.value = 1; signal(mutex); numReaders = 0; m If a writer present, no other writers and no readers. } do reading (could pass in pointer to Why? void writer (){ read function) wait( okToWrite); r Is Producer/Consumer a subset of this? do writing (could pass wait(mutex ); m Producers and consumers are both writers in pointer to write function) numReaders --; m Producer = writer type A; Consumer = writer type B and if (numReaders == 0) no readers signal(okToWrite); signal(okToWrite ); //ok to write again } m What might be a reader? Report current num full. signal (mutex); Can we do better? Fairness? -9 } -10 Monitor solution to Semaphore Solution to Readers/ This one favors writers; readers/writers How? Can readers starve? Writers (Fair) Monitor readersWriters { void startWrite() { semaphore_t readCountMutex, incoming, next; int numReaders = 0; BOOL writeInProgress = while (numReaders || int numReaders; writeInProgress){ FALSE; BOOL writeInProgress, readInProgress; int okToWriteQueued = 0; okToWriteQueued++; conditionVariable okToWrite; wait( okToWrite); void init{ conditionVariable okToRead; okToWriteQueued-- ; } readCountMutex.value = 1; void startRead () { writeInProgress = TRUE; incoming.value = 1; while (writeInProgress || } okToWriteQueued){ next.value = 1; wait (okToRead); void finishWrite(){ numReaders = 0; } writeInProgress = FALSE; writeInProgress = FALSE; numReaders ++; if ( okToWriteQueued){ signal( okToRead ); signal( okToWrite); readInProgress = FALSE; } } else { } signal(okToRead); void finishRead(){ } numReaders--; if (numReaders == 0){ } signal( okToWrite); } //end monitor -11 -12 } 2 Semaphore Solution to Readers/ Remember void reader (){ Writers (Fair) wait(incoming); void writer (){ if (!readInProgress) { wait (incoming); wait (next); r Game is obtaining highest possible degree of wait(next); } concurrency and greatest ease of programming wait(readCountMutex); writeInProgress = TRUE; numReaders++; r Tension readInProgress = TRUE; signal(readCountMutex); m Simple and high granularity locks easy to program //Let someone else move on //to wait on next m Simple and high granularity locks often means low //If next on incoming is signal(incoming); //writer will block on next concurrency //If reader will come in signal(incoming); do writing r Getting more concurrency means do reading m Finer granularity locks, more locks writeInProgress = FALSE; m if (next.value == 0){ wait(readCountMutex); More complicated rules for concurrent access numReaders--; signal (next); if (numReaders == 0){ } readInProgress = FALSE; } if (next.value == 0){ signal (next); } } signal(readCountMutex); -13 -14 Semaphore Solution to Dining Dining-Philosophers Problem Philosophers Problem? //array of chopsticks, chopstick i is philosopher 0 gets chopstick 0 to the right of philosopher i philosopher 1 gets chopstick 1 void philosophersLife(int i){ …. semaphore_t while (1) { int rightChopstick, leftChopstick; philosopher N gets chopstick N chopstick[NUM_PHILOSOPHERS]; think(); //figure out which chopsticks I need Deadlock! Solution? rightChopstick = i; void init(){ leftChopstick = i -1+ NUM_PHILOSOPHERS % NUM_PHILOSOPERS; //grab chopsticks for (i=0; i< NUM_PHILOSOPHERS; i++) wait(chopstick[rightChopstick]) wait(chopstick[leftChopstick ]); chopstick[i].value = 1; eat(); } //putdown chopsticks signal(chopstick[ rightChopstick]) signal(chopstick[ leftChopstick]); } } -15 -16 Deadlock Fixing Dining Philosophers r Deadlock exists in a set of r Make philosophers grab both chopsticks processes/threads when all they need atomically processes/threads in the set are waiting m Maybe pass around a token (lock) saying who for an event that can only be caused by can grab chopsticks another process in the set (which is also m Get a global lock before can lock any chopsticks waiting!). r Make a philosopher give up a chopstick r Dining Philosophers is a perfect example. r Others? Each holds one chopstick and will wait forever for the other. -17 -18 3 Cycle in Resource Allocation Resource Allocation Graph Graph Philosopher 1 has chopstick 1 and wants chopstick 0 r Deadlock can be described through a resource allocation graph Chopstick 0 Philosopher 1 Chopstick 1 r Each node in graph represents a Philosopher process/thread or a resource Cycle: P0, C3, P3, C2, P2, 2 has chopstick 2 Philosopher 0 C1, P1, C0, P0 Philosopher 2 r An edge from node P to R indicates that and wants process P had requested resource R chopstick 1 r An edge from node R to node P indicates Chopstick 3 Chopstick 2 that process P holds resource R Philosopher 0 has Philosopher 3 r If graph has cycle, deadlock may exist. If chopstick 0 and wants Philosopher 3 has chopstick 3 chopstick 3 graph has no cycle, deadlock cannot exist. and wants chopstick 2 wait(chopstick[i]) wait(chopstick[(i-1) % NUM_PHILOSOPHERS]) -19 -20 Better Semaphore Solution to No Cycle in Resource Allocation Dining Philosophers Graph Chopstick 0 Philosopher 1 Chopstick 1 void philosophersLife(int i){ Always wait for low chopstick first No cycle! while (1) { No deadlock! think(); Why better? if ( rightChopstick < leftChopstick}{ This is not the Philosopher 2 Philosopher 0 wait(chopstick[rightChopstick ]); One philosopher only possible wait(chopstick[leftChopstick]); reaches right first when outcome. P1 } else { all others reach left could get wait(chopstick[leftChopstick]); chopstick 0 Chopstick 3 wait(chopstick[rightChopstick ]); Two philsophers reach first, similarly Chopstick 2 } for same one and one will P3 could get Philosopher 3 lose; The one who wins chopstick 3 eat(); will get both chopsticks first. and finish – allowing Regardless, if ( rightChopstick < leftChopstick}{ signal( rightChopstick); everyone to finish someone will wait(chopstick[rightChopstick ]); signal( leftChopstick); eventually get both their wait(chopstick[leftChopstick]); chopsticks and } else { } No circular wait! No be able to wait(chopstick[leftChopstick]); wait(chopstick[rightChopstick ]); } deadlock!! finish -21 } -22 Conditions for Deadlock Deadlock Prevention r Deadlock can exist only if the following four r Four necessary and sufficient conditions conditions are met; for deadlock m Mutual Exclusion – some resource must be held m Mutual Exclusion exclusively m Hold and Wait m Hold and Wait – some process must be holding one resource and waiting for another m No
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages9 Page
-
File Size-