1 / 33

Concurrency: Mutual Exclusion and Synchronization

Concurrency: Mutual Exclusion and Synchronization. Chapter 5. Critical Sections & Mutual Exclusion. shared double balance ; Code for p 1 Code for p 2 . . . . . . balance = balance + amount; balance = balance - amount; . . . . . . balance += amount. balance -= amount. Shared.

stu
Télécharger la présentation

Concurrency: Mutual Exclusion and Synchronization

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Concurrency: Mutual Exclusion and Synchronization Chapter 5

  2. Critical Sections & Mutual Exclusion shared double balance; Code for p1Code for p2 . . . . . . balance = balance + amount; balance = balance - amount; . . . . . . balance += amount balance -= amount Shared balance Assembly code for p1 Assembly code for p2 load R1, balance load R1, balance load R2, amount load R2, amount add R1, R2 sub R1, R2 store R1, balance store R1, balance

  3. Critical Sections (cont.) • Mutual exclusionOnly one process can be in the critical section at a time Without mutual exclusion, results of multiple execution are notconsistent • There is a race to execute critical sections • The sections may be defined by different code in different processes. Therefore, it is not easy for compilers to detect them Need an OS mechanism so programmer can resolve races Some Possible OS Mechanisms • Disable interrupts • Software solution – locks, semaphores

  4. Disabling Interrupts shared double balance; Code for p1Code for p2 disableInterrupts(); disableInterrupts(); balance = balance + amount; balance = balance - amount; enableInterrupts(); enableInterrupts(); • Disabling interrupts guarantees mutual exclusion, but … Disadvantages • A user process can easily abuse this privilege and hence should not be available to a user process. • Interrupts could be disabled arbitrarily long • We only want to prevent p1 and p2 from interfering with one another; this prevents any other process pk to execute • In a Multiprocessor system, disabling interrupts in one processor will not disable it in another process and hence mutual exclusion is not guaranteed

  5. Using a lock Variable shared booleanlock = FALSE; shared double balance; Code for p1Code for p2 /* Acquire the lock *//* Acquire the lock */ while (lock) /*loop */ ; while (lock) /*loop */ ; lock = TRUE; lock = TRUE; /* Execute critical sect *//* Execute critical sect */ balance = balance + amount; balance = balance - amount; /* Release lock *//* Release lock */ lock = FALSE; lock = FALSE; • Access to lock is not atomic, race condition is still there! • Is it possible to solve the problem?

  6. New Solution shared booleanlock = FALSE; shared list L; Code for p1Code for p2 . . . . . . get(lock);get(lock); <execute critical section>;<execute critical section>; release(lock);release(lock); . . . . . . However, get(lock) and release(lock) operations must be atomic !

  7. Important considerations for software locks • Mutual exclusion: Only one process at a time in the Critical Section (CS) • Only the processes competing for a CS must be considered for resolving who enters the CS next. • Once a process attempts to enter its CS, it should not be postponed indefinitely  NO STARVATION! (After requesting entry, only a bounded number of other processes may enter before the requesting process) • No deadlock or starvation should occur • A process should not be delayed access to a critical section when there is no other process using it • No assumptions should be made about the relative speeds of processes or the number of competing processes

  8. Dijkstra’s Semaphore • Invented in the 1960s • Conceptual OS mechanism, with no specific implementation defined (could be get()/release()) • Basis of all contemporary OS synch. mechanisms • A semaphore, s, is a nonnegative integer variable that can only be changed or tested by these two atomic (indivisible / uninterruptable) functions: P(s) : [ while(s == 0) {wait}; s = s – 1; ] V(s) : [ s = s + 1;]

  9. Semaphore solution structsemaphore { intcount; queueTypequeue; } void get(semaphore s) disable_interrupts(); { s.count--; if (s.count < 0) {place this process in s.queue; block this process } enable_interrupts(); } void release(semaphore s) {disable_interrupts(); s.count++; if (s.count <= 0) { remove a process P from s.queue; place process P on ready queue; } enable_interrupts(); } get( )  P( )  wait( )  pthread_mutex_lock() release( )  V( )  signal( )  pthread_mutex_unlock()

  10. Shared Account Problem • P0() • { • . . . • /* Enter the CS */ • P(mutex); • balance += amount; • V(mutex); • . . . • } • P1() • { • . . . • /* Enter the CS */ • P(mutex); • balance -= amount; • V(mutex); • . . . • } semaphore mutex = 1; pthread_create(P0, 0); pthread_create(P1, 0);

  11. Semaphore/Critical Section example A is done! What is going to happen now?

  12. Processing Two Critical Sections shared lock1 = FALSE; shared lock2 = FALSE; Code for p1 . . . /* Enter CS-1 */ get(lock1); <critical section 1>; release(lock1); <other computation>; /* Enter CS-2 */ get(lock2); <critical section 2>; release(lock2); . . . shared lock1 = FALSE; shared lock2 = FALSE; Code for p2 . . . /* Enter CS-2*/ get(lock2); <critical section 2>; release(lock2); <other computation>; /* Enter CS-1 */ get(lock1); <critical section 1>; release(lock1); . . .

  13. Deadlockmay occur if locks are not used properly! shared boolean lock1 = FALSE; shared boolean lock2 = FALSE; Code for p1Code for p2 . . . . . . get(lock1); get(lock2); <delete element>; <update length>; /* Enter CS to update length */ /* Enter CS to add element */ get(lock2); get(lock1); <update length>; <add element>; release(lock2); releaselock1); release(lock1); release(lock2); . . . . . .

  14. OS concerns related to concurrency • Synchronization (support for mutual exclusion) • Deadlock • Resouce Allocation / deallocation • Processor • Memory • Files • I/O devices • Protection of data/resources (access control for sharing)

  15. Producer/Consumer Problem • One or more producers are generating data and placing these in a buffer • A single consumer is taking items out of the buffer one at time Producer: while (true) { /* produce item v */ b[in] = v; in++; } Consumer: while (true) { while (in <= out) /* wait */; w = b[out]; out++; /* consume item w */ }   Infinite Buffer Since Buffer b[], “in” and “out” pointers are all shared, these solutions do not work! Only one producer or consumer should access the buffer at any one time !

  16. Producer/Consumer using a Circular Buffer Consumer: while (true) { while (in == out) /* do nothing */; w = b[out]; out = (out + 1) % n; /* consume item w */ } Producer: while (true) { /* produce item v */ while((in + 1)%n == out) /* do nothing */; b[in] = v; in = (in + 1) % n } Since Buffer b[], “in” and “out” pointers are all shared, these solutions do not work, either!

  17. A Solution to Bounded-Buffer Producer/Consumer Problem /* lock for Full Pool */ /* of items in Full Pool */ Bounded Buffer Empty Pool Producer Consumer Producer Consumer Producer Full Pool

  18. Readers-Writers Problem Writer Reader Writer Reader Writer Reader Writer Reader Writer Reader Writer Reader Writer Reader Reader Shared Resource

  19. Readers-Writers Problem Writer Writer Writer Writer Writer Writer Writer Reader Reader Reader Reader Reader Reader Reader Reader Shared Resource

  20. Readers-Writers Problem Reader Writer Reader Writer Reader Writer Reader Writer Reader Writer Reader Writer Reader Reader Writer Shared Resource

  21. First Solution reader() { while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); P(mutex); readCount--; if(readCount == 0) V(writeBlock); V(mutex); } } resourceType *resource; intreadCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } } • First reader competes with writers • Last reader signals writers

  22. 2 4 5 3 1 First Solution reader() { while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); P(mutex); readCount--; if(readCount == 0) V(writeBlock); V(mutex); } } resourceType *resource; intreadCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } } • First reader competes with writers • Last reader signals writers • Any writer must wait for all readers • Readers can starve writers • “Updates” can be delayed forever not desirable!

  23. 4 5 3 2 1 Writers Take Precedence reader() { while(TRUE) { <other computing>; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } intreadCount=0, writeCount=0; semaphore mutex1=1, mutex2=1; Semaphore readBlock=1,writeBlock=1 writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  24. 5 4 3 2 1 Writers Take Precedence reader() { while(TRUE) { <other computing>; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } intreadCount=0, writeCount=0; semaphore mutex1=1, mutex2=1; semaphore readBlock=1,writeBlock=1 writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  25. 6 7 5 4 3 Writers Take Precedence reader() { while(TRUE) { <other computing>; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } intreadCount=0, writeCount=0; semaphore mutex1=1, mutex2=1; semaphore readBlock=1,writeBlock=1 writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } } • Writers can starve readers • “Reads” can be delayed forever • Not desirable, either !

  26. 4 3 2 1 Fair to Readers and Writers ? reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } int readCount = 0, writeCount = 0; semaphore mutex1 = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; writer() { while(TRUE) { <other computing>; P(writePending); P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); V(writePending); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  27. 4 5 3 2 1 Fair to Readers and Writers ? reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } int readCount = 0, writeCount = 0; semaphore mutex1 = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; writer() { while(TRUE) { <other computing>; P(writePending); P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); V(writePending); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  28. 4 5 3 Fair to Readers and Writers ? reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } int readCount = 0, writeCount = 0; semaphore mutex1 = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; writer() { while(TRUE) { <other computing>; P(writePending); P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); V(writePending); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  29. 4 5 6 3 Fair to Readers and Writers ? reader() { while(TRUE) { <other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } } int readCount = 0, writeCount = 0; semaphore mutex1 = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; writer() { while(TRUE) { <other computing>; P(writePending); P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); V(writePending); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } }

  30. Dining Philosophers while(TRUE) { think(); get2chopsticks(); eat(); }

  31. Dining Philosophers Anything wrong with this code? while(TRUE) { think(); getchopstick-R(); getchopstick-L(); eat(); }

  32. **here The Barbershop Problem semaphore max_capacity = 20, sofa = 4, barber_chair = 3, coord = 3; semaphorecust_ready = 0, finished = 0, leave_b_chair = 0, payment= 0, receipt = 0; void customer () { wait(max_capacity); enter_shop(); wait(sofa); sit_on_sofa(); wait(barber_chair); get_up_from_sofa(); signal(sofa); sit_in_barber_chair; signal(cust_ready); wait(finished); leave_barber_chair(); signal(leave_b_chair); pay(); signal(payment); wait(receipt); exit_shop(); signal(max_capacity) } • void barber() • { • while (true) • { • wait(cust_ready); • wait(coord); • cut_hair(); • signal(coord); • signal(finished); • wait(leave_b_chair); • signal(barber_chair); • } • }

  33. The Barbershop (cont.) void cashier() { while (true) { wait(payment); wait(coord); accept_pay(); signal(coord); signal(receipt); } } void main() { parbegin (customer, . . . 50 times . . . customer, barber, barber, barber, cashier); }

More Related