1 / 23

Condition Variables

Condition Variables. Motivation for Monitors. Semaphores are a big step from the low-level loads and stores However, semaphores are used for both mutual exclusion and synchronization The idea of monitors is to separate these two concerns. Monitor Defined.

Download Presentation

Condition Variables

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. Condition Variables

  2. Motivation for Monitors • Semaphores are a big step from the low-level loads and stores • However, semaphores are used for both mutual exclusion and synchronization • The idea of monitors is to separate these two concerns

  3. Monitor Defined • Monitor: a lock + condition variables • Lock: provides mutual exclusion to shared data • Condition variable: provides a queue for waiting threads inside a critical section

  4. Locks • A lock provides two operations: • Lock::Acquire() • Wait until the lock is free, then grab it • Lock::Release() • Unlock, wake up anyone waiting to Acquire • A lock is initially free

  5. More on Locks • Always acquire a lock before accessing a shared data structure • Always release the lock after finishing with the shared data structure

  6. An Example of Using Locks AddToQueue() { Lock.Acquire(); // put 1 item to the queue Lock.Release(); } RemoveFromQueue() { Lock.Acquire(); // if something on the queue // remove 1 item form the queue Lock.Release(); return item; }

  7. Condition Variables • We need additional mechanisms to wait inside locked regions • However, holding the lock while waiting prevents other threads from entering the locked region • Condition variables make it possible to sleep inside a critical section • Atomically release the lock & go to sleep

  8. Condition Variables • Each condition variable • Consists of a queue of threads • Provides three operations • Wait(); • Atomically release the lock and go to sleep • Reacquire lock on return • Signal(); • Wake up one waiting thread, if any • Broadcast(); • Wake up all waiting threads

  9. Condition Variables • Note • The three operations can only be used inside locked regions

  10. An Example of Using Condition Variables AddToQueue() { lock.Acquire(); // put 1 item to the queue condition.Signal(&lock); lock.Release(); } RemoveFromQueue() { lock.Acquire(); while nothing on queue condition.Wait(&lock); lock.Release(); return item; }

  11. Semaphores vs. Monitors • Can we implement monitors with semaphores? Wait() { P(s); } Signal() { V(s); }

  12. Semaphores vs. Monitors • Not quite… • Condition variables only work inside a lock • Using semaphores inside a lock may deadlock

  13. Semaphores vs. Monitors • Condition variables have no history, but semaphores have • Signal() with an empty queue does nothing • A subsequent Wait() will wait • V() increments semaphore • A subsequent P() will not wait

  14. Monitor support in pthread • Monitor = lock + condition variable • Lock in pthread: mutex • Mutex operations: • Creation: pthread_mutex_t my = PTHREAD_MUTEX_INITIALIZER • Destroying: pthread_mutex_destroy(pthread_mutex_t *mutex); • Locking and unlocking mutexes pthread_mutex_lock(pthread_mutex_t *mutex); pthread_mutex_trylock(pthread_mutex_t *mutex); pthread_mutex_unlock(pthread_mutex_t *mutex);

  15. Condition variables in pthread • Waiting and signaling on condition variables • Data type: pthread_cond_tdata_cond = PTHREAD_COND_INITIALIZER; • Routines • pthread_cond_wait(condition, mutex) • Blocks the thread until the specific condition is signalled. • Should be called with mutex locked • Automatically release the mutex lock while it waits • When return (condition is signaled), mutex is locked again • pthread_cond_signal(condition) • Wake up a thread waiting on the condition variable. • Called after mutex is locked, and must unlock mutex after • pthread_cond_broadcast(condition) • Used when multiple threads blocked in the condition

  16. Condition Variables • While mutexes implement synchronization by controlling thread access to data, condition variables allow threads to synchronize based upon the actual value of data. • Without condition variables, The programmer would need to have threads continually polling (usually in a critical section), to check if the condition is met. • A condition variable is a way to achieve the same goal without polling(a.k.a. “busy wait”)

  17. Condition Variables • Useful when a thread needs to wait for a certain condition to be true. • In pthreads, there are four relevant procedures involving condition variables: • pthread_cond_init(pthread_cond_t *cv, NULL); • pthread_cond_destroy(pthread_cond_t *cv); • pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *lock); • pthread_cond_signal(pthread_cond_t *cv);

  18. Creating and Destroying Conditional Variables • Condition variables must be declared with typepthread_cond_t, and must be initialized before they can be used. • Statically, when it is declared. For example: pthread_cond_t myconvar = PTHREAD_COND_INITIALIZER; • Dynamically pthread_cond_init(cond, attr); Upon successful initialization, the state of the condition variable becomes initialized. • pthread_cond_destroy(cond)shouldbe used to free a condition variable that isno longer needed.

  19. pthread_cond_wait • pthread_cond_wait(cv, lock) is called by a thread when it wants to block and wait for a condition to be true. • It is assumed that the thread has locked the mutex indicated by the second parameter. • The thread releases the mutex, and blocks until awakened by apthread_cond_signal() call from another thread. • When it is awakened, it waits until it can acquire the mutex, and once acquired, it returns from thepthread_cond_wait()call.

  20. pthread_cond_signal • pthread_cond_signal()checks to see if there are any threads waiting on the specified condition variable. If not, then it simply returns. • If there are threads waiting, then one is awakened. • There can be no assumption about the order in which threads are awakened bypthread_cond_signal()calls. • It is natural to assume that they will be awakened in the order in which they waited, but that may not be the case… • Use loop or pthread_cond_broadcast()to awake all waiting threads.

  21. typedef struct { pthread_mutex_t *lock; pthread_cond_t *cv; int *ndone; int id; } TStruct; #define NTHREADS 5 void *barrier(void *arg) { TStruct *ts; int i; ts = (TStruct *) arg; printf("Thread %d -- waiting for barrier\n", ts->id); pthread_mutex_lock(ts->lock); *ts->ndone = *ts->ndone + 1; if (*ts->ndone < NTHREADS) { pthread_cond_wait(ts->cv, ts->lock); } else { for (i = 1; i < NTHREADS; i++) pthread_cond_signal(ts->cv); } pthread_mutex_unlock(ts->lock); printf("Thread %d -- after barrier\n", ts->id); }

  22. main() { TStruct ts[NTHREADS]; pthread_t tids[NTHREADS]; int i, ndone; pthread_mutex_t lock; pthread_cond_t cv; void *retval; pthread_mutex_init(&lock, NULL); pthread_cond_init(&cv, NULL); ndone = 0; for (i = 0; i < NTHREADS; i++) { ts[i].lock = &lock; ts[i].cv = &cv; ts[i].ndone = &ndone; ts[i].id = i; } for (i = 0; i < NTHREADS; i++) pthread_create(tids+i, NULL, barrier, ts+i); for (i = 0; i < NTHREADS; i++) pthread_join(tids[i], &retval); printf("done\n"); }

  23. Output Thread 0 -- waiting for barrier Thread 1 -- waiting for barrier Thread 2 -- waiting for barrier Thread 3 -- waiting for barrier Thread 4 -- waiting for barrier Thread 4 -- after barrier Thread 0 -- after barrier Thread 1 -- after barrier Thread 2 -- after barrier Thread 3 -- after barrier done

More Related