Communication: Condition Variable

Condition Variable (1)

Communication:

  • One thread waits for a certain event to happen

  • The event is produced by another thread

  • The waiting thread does not consume and CPU time while waiting (polling is dumb)

  • Solution in Windows: WIN32 Events (auto-reset, manual-reset)

POSIX is different: Condition Variable

  • No state (as opposed to WIN32 Events — set/unset)

  • Operations wait() and signal()

  • Useless on its own

  • Building block to build custom communication mechanisms around custom conditions

Condition Variable (2)

Sample conditions (predicates, in POSIX parlance):

  • Event has been set

  • Message queue is not empty anymore

  • Message queue is not full anymore

  • Semaphore count is not zero anymore

Condition is coupled with a state which is protected by a mutex. For example:

  • Boolean flag “set/unset”

  • Message queue implementation (linked list?)

Condition Variable: wait()

int pthread_cond_wait(
    pthread_cond_t *cond,
    pthread_mutex_t *mutex);

Danger

In an atomic operation (otherwise ⟶ “Lost Wakeup”)

  • Releases mutex

  • Suspends caller until condition variable is signaled by another thread

Condition Variable: signal()

int pthread_cond_signal(pthread_cond_t *cond);

Again, in an atomic operation:

  • Wakes one waiter if any

  • Lets him acquire the mutex

Example: WIN32 Auto Reset Event (1)

Setting the event
void set_autoreset_event(Event* ev)
{
    pthread_mutex_lock(&ev->mutex);
    ev->value = 1;
    pthread_mutex_unlock(&ev->mutex);
    pthread_cond_signal(&ev->is_set);
}

Example: WIN32 Auto Reset Event (2)

Waiting for the event
void wait_autoreset_event(Event* ev)
{
    pthread_mutex_lock(&ev->mutex);
    while (ev->value != 1) {
        pthread_cond_wait(&ev->is_set, &ev->mutex);
        /* mutex acquiriert */
    }
    ev->value = 0; /* "autoreset" */
    pthread_mutex_unlock(&ev->mutex);
}

Condition Variable: Checking the Predicate

Use while instead of if , because …

  • Spurious wakeups are possible (for example if the PThread implementation is using signals internally)

  • Multiple waiters are woken (broadcast)

    • Predicate is true, but the first thread invalidates it immediately

Condition Variable: Initialization

int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *cond,
       const pthread_condattr_t *attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  • Dynamic initialization using pthread_cond_init()/pthread_cond_destroy()

  • attr == NULL ⟶ default condition variable

  • Static initialization using PTHREAD_COND_INITIALIZER

Condition Variable: Miscellaneous

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_timedwait(
    pthread_cond_t *cond,
    pthread_mutex_t *mutex,
    const struct timespec *abstime);