Presentation is loading. Please wait.

Presentation is loading. Please wait.

Dr. Xiao Qin Auburn University

Similar presentations


Presentation on theme: "Dr. Xiao Qin Auburn University "— Presentation transcript:

1 COMP7330/7336 Advanced Parallel and Distributed Computing Condition Variables
Dr. Xiao Qin Auburn University Slides are adopted and modified from Drs. Ananth Grama, Anshul Gupta, George Karypis, and Vipin Kumar

2 Review: Semaphore Semaphore S: integer variable Two atomic operations
wait() and signal() Also called P() and V() Counting semaphore – integer value can range over an unrestricted domain Binary semaphore – integer value can range only between 0 and 1 Same as a mutex lock Synchronization tool that provides more sophisticated ways (than Mutex locks) for process to synchronize their activities. Semaphore S – integer variable Can only be accessed via two indivisible (atomic) operations wait() and signal() Originally called P() and V() Definition of the wait() operation wait(S) { while (S <= 0) ; // busy wait S--; } Definition of the signal() operation signal(S) { S++;

3 Condition Variables for Synchronization
Allows a thread to block itself until specified data reaches a predefined state. A condition variable is associated with this predicate. When the predicate becomes true, the condition variable is used to signal one or more threads waiting on the condition. A single condition variable may be associated with more than one predicate. A condition variable allows a thread to block itself until specified data reaches a predefined state. A condition variable is associated with this predicate. When the predicate becomes true, the condition variable is used to signal one or more threads waiting on the condition. A single condition variable may be associated with more than one predicate. A condition variable always has a mutex associated with it. A thread locks this mutex and tests the predicate defined on the shared variable. If the predicate is not true, the thread waits on the condition variable associated with the predicate using the function pthread_cond_wait.

4 Condition Variables for Synchronization
Why do we need a mutex? Has a mutex associated with it. A thread locks this mutex and tests the predicate defined on the shared variable. If the predicate is not true, the thread waits on the condition variable associated with the predicate using the function pthread_cond_wait. A condition variable allows a thread to block itself until specified data reaches a predefined state. A condition variable is associated with this predicate. When the predicate becomes true, the condition variable is used to signal one or more threads waiting on the condition. A single condition variable may be associated with more than one predicate. A condition variable always has a mutex associated with it. A thread locks this mutex and tests the predicate defined on the shared variable. If the predicate is not true, the thread waits on the condition variable associated with the predicate using the function pthread_cond_wait.

5 Producer/Consumer Implementation with Locks
char buffer[SIZE]; int count = 0, head = 0, tail = 0; static struct lock *mutex; mutex = lock_create(“mutex for cv”); void producer(char c) { lock_acquire(mutex); count++; buffer[head] = c; head++; if (head == SIZE) { head = 0; } lock_release(mutex); What is the problem here? char consumer() { char c; lock_acquire(mutex); count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; } lock_release(mutex); return c; Let’s consider the producer/consumer sample to show how to use condition variables We start this example with locks. 3. No need to use static here; just a demonstration

6 How to handle the empty/full cases using locks?
void producer(char c) { lock_acquire(mutex); while (count == SIZE) { lock_release(mutex); } count++; buffer[head] = c; head++; if (head == SIZE) head = 0; char consumer() { char c; lock_acquire(mutex); while (count == 0) { lock_release(mutex); } count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; return c; Why lock and unlock here? Why release in while? Do not block while waiting. For fair compitition Which lock_acqure and lock_release are a pair? Which lock_acqure() and lock_release() are a pair? Can we improve this code using wait and signal?

7 Producer: how to use condition variables?
void producer(char c) { lock_acquire(mutex); while (count == SIZE) { cv_wait(notFull, mutex); } count++; buffer[head] = c; head++; if (head == SIZE) { head = 0; cv_signal(notEmpty, mutex); lock_release(mutex);

8 Consumer: how to use condition variables?
char consumer() { char c; lock_acquire(mutex); while (count == 0) { cv_wait(notEmpty, mutex); } count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; cv_signal(notFull, mutex); lock_release(mutex); return c;

9 Condition Variables Comment: move unlock below wakeup Reference:

10 How to implement cv_signal()?
void cv_signal(struct cv *cv, struct lock *lock) { use assert to check cv and lock; turn off interrupts; /* Question: How to implement the following IF */ if (this thread does not hold lock) panic("cv_signal error: cv %s at %p, lock %s at %p.\n", cv->name, cv, lock->name, lock); wakeup one thread using indicator “cv”; turn on interrupts to the previous level; } cv shouldn’t be NULL lock shouldn’t be NULL cv_signal does’t need lock as an input.

11 Condition Variables for Synchronization
Pthreads provides the following functions for condition variables: int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_destroy(pthread_cond_t *cond); The pthread_cond_broadcast() function wakes up all threads that are currently waiting on the condition variable specified by cond. If no threads are currently blocked on the condition variable, this call has no effect. A destroyed condition variable object can be reinitialized usingpthread_cond_init(); the results of otherwise referencing the object after it has been destroyed are undefined.

12 Producer-Consumer Using Condition Variables
pthread_cond_t cond_queue_empty, cond_queue_full; pthread_mutex_t task_queue_cond_lock; int task_available; /* other data structures here */ main() { /* declarations and initializations */ task_available = 0; pthread_init(); pthread_cond_init(&cond_queue_empty, NULL); pthread_cond_init(&cond_queue_full, NULL); pthread_mutex_init(&task_queue_cond_lock, NULL); /* create and join producer and consumer threads */ }

13 Producer-Consumer Using Condition Variables
void *producer(void *producer_thread_data) { int inserted; while (!done()) { create_task(); pthread_mutex_lock(&task_queue_cond_lock); while (task_available == 1) pthread_cond_wait(&cond_queue_empty, &task_queue_cond_lock); insert_into_queue(); task_available = 1; pthread_cond_signal(&cond_queue_full); pthread_mutex_unlock(&task_queue_cond_lock); }

14 Producer-Consumer Using Condition Variables
void *consumer(void *consumer_thread_data) { while (!done()) { pthread_mutex_lock(&task_queue_cond_lock); while (task_available == 0) pthread_cond_wait(&cond_queue_full, &task_queue_cond_lock); my_task = extract_from_queue(); task_available = 0; pthread_cond_signal(&cond_queue_empty); pthread_mutex_unlock(&task_queue_cond_lock); process_task(my_task); }

15 Controlling Thread and Synchronization Attributes
The Pthreads API allows a programmer to change the default attributes of entities using attributes objects. An attributes object is a data-structure that describes entity (thread, mutex, condition variable) properties. Once these properties are set, the attributes object can be passed to the method initializing the entity. Enhances modularity, readability, and ease of modification.

16 Attributes Objects for Threads
Use pthread_attr_init to create an attributes object. Individual properties associated with the attributes object can be changed using the following functions: pthread_attr_setdetachstate, pthread_attr_setguardsize_np, pthread_attr_setstacksize, pthread_attr_setinheritsched, pthread_attr_setschedpolicy, and pthread_attr_setschedparam

17 Attributes Objects for Mutexes
Initialize the attrributes object using function: pthread_mutexattr_init. The function pthread_mutexattr_settype_np can be used for setting the type of mutex specified by the mutex attributes object. pthread_mutexattr_settype_np ( pthread_mutexattr_t *attr, int type); Here, type specifies the type of the mutex and can take one of: PTHREAD_MUTEX_NORMAL_NP PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_ERRORCHECK_NP the np suffix stands for non-portable That means the same thread can lock the same mutex twice and won't deadlock. Of course it also needs to unlock it twice, otherwise no other thread can obtain the mutex. Reference: If the mutex is already locked by the calling thread, the behavior of pthread_mutex_lock depends on the type of the mutex. If the mutex is of the “normal” type, the calling thread is suspended until the mutex is unlocked, thus effectively causing the calling thread to deadlock. If the mutex is of the ‘‘error checking’’ type, pthread_mutex_lock returns immediately with the error code EDEADLK. If the mutex is of the ‘‘recursive’’ type, pthread_mutex_lock succeeds and returns immediately, recording the number of times the calling thread has locked the mutex. An equal number of pthread_mutex_unlock operations must be performed before the mutex returns to the unlocked state.

18 See condition_variable.c

19 What are the differences between Condition Variable (CV) and Mutex?
CV is high-level synchronization primitive CV = lock + signaling mechanism CV: like a stop light (for collaboration) Mutex: like a gate or yield sign (for competition) Reference: A Semephore is a conditional variable suited for inter thread communications. A semephore can be used with specific functions to block thread execution without using cpu clock cycles. A semapore is a stop light which tells a thead to go or stop in a cpu friendly manor. A mutex like a semaphore is cpu cycles friendly. Only a mutex doens't act like a stop light. It acts as a gate, or yeild sign. If two threads are headed for collision when they reach the mutex, one will be paused just long enough to divert the desaster rather than blocking on a semephore until the semephore is cleared. Reference:

20 In the following two cases, should we use condition variable or Mutex?
Multiple threads are accessing a shared Table One thread preprocess data to be sorted by another thread


Download ppt "Dr. Xiao Qin Auburn University "

Similar presentations


Ads by Google