cs24-22fa pthread_cond_wait

Introduction to Computing Systems (Fall 2022)

Name

pthread_cond_wait - wait on a condition

Synopsis

#include <pthread.h>

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

Description

The pthread_cond_wait() function shall block on a condition variable. It shall be called with mutex locked by the calling thread or undefined behavior results.

These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means “atomically with respect to access by another thread to the mutex and then the condition variable”. That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.

Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.

When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_wait() functions may occur. Since the return from pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.

Example

#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>

bool done = false;
pthread_mutex_t mutex;
pthread_cond_t cond;

void *child(void *arg) {
    printf("child\n");

    // Must lock before updating condition, else get race condition
    pthread_mutex_lock(&mutex);
    done = 1;
    // Signal that at least one thread waiting on the condition
    // should wake up to check on the condition variable
    pthread_cond_signal(&cond);
    // Unlock since we are no longer setting the condition
    pthread_mutex_unlock(&mutex);

    return NULL;
}

int main(int argc, char *argv[]) {
    printf("parent: begin\n");

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    // Run a child thread that will eventually set done to 1
    pthread_t p;
    pthread_create(&p, NULL, child, NULL);

    // Must lock before checking condition, else get race condition
    pthread_mutex_lock(&mutex);
    while (!done) {
        // Upon call, pthread_cond_wait releases the mutex
        pthread_cond_wait(&cond, &mutex);
        // Upon return, pthread_cond_wait locks the mutex
        
        // Spurious wakeups may happen, so the condition
        // must be reevaluated upon return of pthread_cond_wait
    }
    printf("Wow! I'm done!\n");

    // Done confirming the condition done != 0, so unlock
    pthread_mutex_unlock(&mutex);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    printf("parent: end\n");
    return 0;
}

Return Value

Upon successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate the error.

See Also

pthread_cond_init(), pthread_cond_destroy(), pthread_cond_signal()