1 / 53

Class Announcement

The TA will shift office hours to tomorrow. Project 0 deadline is extended to next Monday, April 13, at noon. A copy of the textbook is reserved in the library. Any issues with Project 0? Lecture on Process/Thread Synchronization. Topics: Critical-section problem, locks, semaphores, condition variables, synchronization in Nachos and Pthreads. Managing race conditions, critical-section properties, and solutions. Locks, semaphores, and conditional variables in critical-section problems. Example code and usage of locks for mutual exclusion and synchronization.

bmorehead
Download Presentation

Class Announcement

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. Class Announcement • TA is expected to add/move office hours to tomorrow for Project 0 • Project 0 deadline is extended to next Monday April 13 noon. • A copy of the text book reserved in the library. • Any Issues for Project 0? • Pass all public tests locally and then fail in submit.cs?

  2. Testfile2 without/with an invalid command ls -l > temp wc temp ls -l -f > temp wc < temp > temp2 sort < temp > temp3 cat temp2 diff temp2 temp3 > temp4 wc temp4 exit ls -l > temp wc temp ls -l -f > temp wc < temp > temp2 sort < temp > temp3 catt temp2 diff temp2 temp3 > temp4 wc temp4 exit

  3. Testfile4 without/with an invalid command ls -l -f | sort > temp ls -l | sort > temp1 diff temp temp1 > temp2 cat < temp | uniq | sort > temp3 diff temp3 temp |sort | wc > temp4 cat temp4 exit ls -l -f | sort > temp ls -l | sort > temp1 diff temp temp1 > temp2 cat < temp | uniq | sort > temp3 catt temp3 | wc diff temp3 temp |sort | wc > temp4 cat temp4 exit Autograding only compares with expected answers for processing all valid commands. Donot test weird cases.

  4. Lecture 5: Process/Thread Synchronization CS170. UCSB. 2015. T. Yang

  5. Topics • The critical-section problem and examples • Solutions • Locks • Semaphores • Condition variables (monitors). • Synchronization in Nachos and Pthreads

  6. Application example that needs synchronization 2 producer threads and 2 consumer threads Shared data

  7. Shared variables in a producer/consumer program • count--number of items available • in -- points to the writeable slot • out -- points to the slot to read out in

  8. Producer Thread Code while (true) { while (count == BUFFER_SIZE) ; // buffer is full, spin buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; } in

  9. Consumer thread while (true) { while (count == 0) ; // Nothing is available. Spin nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; } out

  10. Race Conditions: Example Count=5 Consumer thread Producer thread Count++; Count--; Is count still 5? Race Conditions: two or more processes (threads) are reading and writing on shared data and the final result depends on who runs precisely & when

  11. Review compiled code Count=5 Consumer thread Producer thread Count++: register1 = count register1 = register1 + 1 count = register1 Count—: register2 = count register2 = register2 - 1 count = register2 Is count still 5?

  12. Executing compiled code Count=5 Consumer thread Producer thread Count++: register1 = count register1 = register1 + 1 count=register1 Count—: register2 = count register2 = register2 - 1 count = register2 Is count still 5? 4, 6? Time

  13. Executing compiled code Count=5 Consumer thread Producer thread Count++: register1 = count register1 = register1 + 1 count = register1 Count—: register2 = count register2 = register2 - 1 count = register2 Time Is count still 5? 4, 6?

  14. Critical-Section Management Critical section: the part of the program where shared variables are accessed

  15. Property of Critical-Section Solutions • Mutual Exclusion – Only one can enter the critical section. Safety property in AD book • Progress - If some processes wish to enter their critical section and nobody is in the critical section, then one of them will enter in a limited time. Liveness property in AD book • Bounded Waiting - If one process starts to wait for entering an critical section, there is a limit on the number of times other processes entering the section before this process enters. Liveness property in AD book

  16. Solution to Critical-section Problem Locks Semaphore Conditional Variables

  17. Lock for Critical-section Problem Acquire lock Critical section Release lock • Thread waits if there is a lock. • It enters the critical after acquiring a lock. • Only the thread who locks can unlock.

  18. Nachos Lock Interface • Lock can be in one of two states: locked or unlocked • class Lock { public: Lock (char *name); //create a lock with unlocked state ~Lock(); void Acquire(); //Atomically waits until the lock is unlocked, and then sets the lock to be locked. void Release(); //Atomically changes the state to be unlocked. Only the thread who owns the lock can release. }

  19. How to use locks • Typically associate a lock with a piece of shared data for mutual execlusion. • When a thread needs to access, it first acquires the lock, and then accesses data. Once access completes, it releases the lock. • Example Lock *k= new Lock (“Lock”); k->Acquire(); Perform critical section operations. k->Release(); }

  20. Synchronization with Locks: Example int a=0; Lock *k; void sum (int p){ int c; k->Acquire(); a=a+1; c=a; k->Release() printf(“%d : a= %d\n”, p,c); } void main() { Thread *t=new Thread (“Child”); k=new Lock(“Lock”); t->Fork(sum,1); sum(0); }

  21. Semaphore for the critical-section problem • Semaphore S – nonnegative integer variable • Can only be accessed /modified via two indivisible (atomic) operations • wait (S) { //also called P() while S <= 0 ; // wait in a queue S--; } • signal (S) { //also called V() //wake up some waiting thread S++; }

  22. Semaphore • Counting semaphore – initial value representing how many threads can be in the critical section. • Binary semaphore (also known as mutex locks) – integer value ranged between 0 and 1. • Provides mutual exclusion Semaphore mutex; // initialized to 1 do { P(mutex); // Critical Section V(mutex); } while (TRUE); • Not recommended by the AD text book (Chapter 5.8), but still widely used.

  23. Semaphores in Nachos • class Semaphore{ public: Semaphore (char *name, int counter); // initial counter value ~Semaphore(); void P(); //Atomically waits until the counter is greater than 0 and then decreases the counter void V(); //Atomically increases the counter }

  24. Synchronization with Semaphore: Example int a=0; Semaphore *s; void sum (int p){ int c; s->P(); a=a+1; c=a; s->V(); printf(“%d : a= %d\n”, p,c); } void main() { Thread *t=new Thread (“Child”); s=new Semaphore(“S”,1); t->Fork(sum,1); sum(0); }

  25. Synchronization in Consumer thread while (true) { while (count == 0) ; // sping waiting nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data for other things } out

  26. Synchronization in Producer/ Consumer threads What is shared? How to synchronize? Consumer loop: while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data and do others Producer loop: Produce next item while (count == BUFFER_SIZE) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; out in count

  27. Synchronization Attempt Deadlock? How to avoid spin? Consumer loop: while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data Producer loop: Produce next item while (count == BUFFER_SIZE) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; out in count

  28. Another Synchronization Attempt Mutual execution? Consumer loop: while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data Producer loop: Produce next item while (count == BUFFER_SIZE) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; out in in count

  29. What can happen with this trace? Consumer 2: while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data and do others Consumer 1 : while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Do other things out in in count

  30. Semaphore for consumer/producer problem • Simplify the problem: • Unbounded buffer • Worry about bounded buffer constraint later • Condition to check: • Is there a data item available to consume? • Not available?  Wait using 1 semaphore

  31. Semaphore for consumer-producer problem with unbounded buffer Semaphore can do more than mutual exclusion, and can synchronize a consumer/producer pipe • Semaphore *data =new Semaphore(“Data”, 0); • Indicate # of data items available for consuming • Consumer thread: while(1) { data-> P(); //wait until an item is available Use data item; } • Producer thread: while(1){ produce next item; data->V(); //notify an item is available }

  32. Semaphore for consumer/producer problem with bounded buffer • What condition to check for bounded buffer? • Conditions to check: • Is there a data item available to consume? • Is there space available to produce a data item? • Wait using two semaphores

  33. Consumer-producer problem with bounded buffer • Two semaphores: • Semaphore *data =new Semaphore(“Data”, 0); • Indicate # of data items available for consuming • Semaphore *space =new Semaphore(“Space”, 10); • Indicate # of 10 data slots available. • Producer thread: while(1){ produce next item; data->V(); //notify item is available }

  34. Consumer-producer problem with bounded buffer • Two semaphores: • Semaphore *data =new Semaphore(“Data”, 0); • Indicate # of data items available for consuming • Semaphore *space =new Semaphore(“Space”, 10); • Indicate # of 10 data slots available. • Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available }

  35. Consumer-producer problem with bounded buffer • Semaphore *data =new Semaphore(“Data”, 0); • Semaphore *space =new Semaphore(“Space”, 10); • Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available } • Consumer thread: while(1){ data->P();//wait until data is available consume next item; }

  36. Consumer-producer problem with bounded buffer • Semaphore *data =new Semaphore(“Data”, 0); • Semaphore *space =new Semaphore(“Space”, 10); • Producer thread: while(1){ space->P();//wait until space is available produce next item; data->V(); //notify data is available } • Consumer thread: while(1){ data->P();//wait until data is available consume next item; space->V();//notify space is available }

  37. Synchronization for pthreads: Mutex pthread_mutex_t mutex; const pthread_mutexattr_t attr; int status; status = pthread_mutex_init(&mutex,&attr); status = pthread_mutex_destroy(&mutex); status = pthread_mutex_unlock(&mutex); status = pthread_mutex_lock(&mutex); - block Thread i …… lock(mutex) …… critical region …… unlock(mutex) ……

  38. Semaphore for Pthreads int status,pshared; sem_t sem; unsigned int initial_value; status = sem_init(&sem,pshared,initial_value); status = sem_destroy(&sem); status = sem_post(&sem); status = sem_wait(&sem);

  39. What now? How to use semaphore with lock? Consumer loop: while (count == 0) ; nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; Use data Producer loop: Produce next item while (count == BUFFER_SIZE) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; out in count

  40. Synchronization with semaphore Consumer loop: data->P(); nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; space->V(); Use data Producer loop: Produce next item space->P();//wait until space is available) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; data->V(); //notify data is available

  41. Synchronization with semaphore/lock? Consumer loop: data->P(); nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; space->V(); Use data Producer loop: Produce next item space->P();//wait until space is available) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; data->V(); //notify data is available

  42. What happens when a consumer does not hod a lock after waking up from data->p()? Consumer 2: data->P(); nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; space->V(); Use data Consumer 1: data->P(); nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; space->V(); Use data

  43. Synchronization with semaphore/lock? Consumer loop: data->P(); nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; space->V(); Use data Producer loop: Produce next item space->P();//wait until space is available) ; buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; data->V(); //notify data is available How to hold a lock immediately after waking up?

  44. Solution to Critical-section Problem Locks Semaphore Conditional Variables

  45. Condition Variables in Nachos • Pair it with a lock • class Condition { public: Condition(char *name); ~Condition(); void Wait(Lock *mylock); //Atomically releases the lock and waits. When it is returned, the lock is reacquired again. void Signal(Lock *myLock); //Wake up one waiting thread to run. The lock is not released. void Broadcast(Lock *myLock); //Wake up all threads waiting on the condition. The lock is not released. }

  46. Condition Variables for consumer-producer problem with unbounded buffer • int avail=0; // # of data items available for consumption • Lock *L; Condition *cv= new Condition (“condition”); • Consumer thread loop: L.Acquire(); if (avail <=0) cv.Wait(L); Fetch next item; avail = avail-1; L.Release(); Do other things • Producer thread loop: L.Acquire(); Add next item; avail = avail+1; cv.Signal(L); //notify an item is available L.Release(); Do other things Can condition still be true after wake-up? How to protect?

  47. Condition Variables for consumer-producer problem with unbounded buffer • int avail=0; // # of data items available for consumption • Lock *L; Condition *cv= new Condition (“condition”); • Consumer thread loop: L.Acquire(); while(avail <=0) cv.Wait(L); Fetch next item; avail = avail-1; L.Release(); Do other things • Producer thread loop: L.Acquire(); Add next item; avail = avail+1; cv.Signal(L); //notify an item is available L.Release(); Do other things

  48. How to Use Condition Variables: Typical Flow • Thread 1 mylock.Acquire(); When condition is not satisfied, cv.Wait(mylock); Critical Section; mylock.Release(); • Thread 2: mylock.Acquire(); When condition can satisfy, cv.Signal(mylock); mylock.Relase();

  49. When to use condition broadcast()? • When waking up one thread to run is not sufficient. • Example: concurrent malloc()/free() for allocation and deallocation of objects with non-uniform sizes.

  50. malloc()/free() with condition broadcast • Initially 10 bytes are free. • m() stands for malloc(). f() for free() Thread 2: m(5) – wait Resume m(5)-succ f(5) –broadcast? Thread 3: m(5) – wait Resume m(5)-succ m(3) –wait Resume m(3)-succ Thread 1: m(10) – succ f(10) –broadcast? m(7) – wait Resume m(7)-wait

More Related