"[Pthread] Run Two Threads in Turn"

Pthread Interfaces

#include <pthread.h>
int pthread_create(pthread_t *tidp,
                   const pthread_attr_t attr,
           void *(*start_rtn)(void *),
           void *arg);
int pthread_join(pthread_t *tidp, void **rval_ptr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);

Precautions of pthread_cond_wait()

Typical Usage of pthread_cond_wait/signal()

thread 1:
    pthread_mutex_lock(&mutex);
    while (!condition)
        pthread_cond_wait(&cond, &mutex);
    /* do something that requires holding the mutex and condition is true */
    pthread_mutex_unlock(&mutex);

thread 2:
    pthread_mutex_lock(&mutex);
    /* do something that might make condition true */
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

Program that Runs Two Threads in Turn

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

pthread_mutex_t mutex_a = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_b = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;

bool is_round_of_a = false;
bool is_round_of_b = false;

void *print_a(void *arg)
{
    while (1) {
        pthread_mutex_lock(&mutex_a);
        /* If thread_c has already sent the signal which means
         * is_round_of_a is also already set to true by thread_c,
         * thread_a just does not wait for the signal anymore. */
        while (!is_round_of_a)
            pthread_cond_wait(&cond_a, &mutex_a);
        printf("a\n");
        is_round_of_a = false;
        pthread_mutex_unlock(&mutex_a);

        /* send signal to thread_b and set is_round_of_b to true */
        pthread_mutex_lock(&mutex_b);
        pthread_cond_signal(&cond_b);
        is_round_of_b = true;
        pthread_mutex_unlock(&mutex_b);
    }

    return (void *)0;
}

void *print_b(void *arg)
{
    while (1) {
        pthread_mutex_lock(&mutex_b);
        /* If thread_a has already sent the signal which means
         * is_round_of_b is also already set to true by thread_a,
         * thread_b just does not wait for the signal anymore. */
        while (!is_round_of_b)
            pthread_cond_wait(&cond_b, &mutex_b);
        printf("b\n");
        is_round_of_b = false;
        pthread_mutex_unlock(&mutex_b);

        /* send signal to thread_a and set is_round_of_a to true */
        pthread_mutex_lock(&mutex_a);
        pthread_cond_signal(&cond_a);
        is_round_of_a = true;
        pthread_mutex_unlock(&mutex_a);
    }

    return (void *)0;
}

int main(int argc, char **argv)
{
    pthread_t tid_a, tid_b;

    pthread_create(&tid_a, NULL, print_a, NULL);
    pthread_create(&tid_b, NULL, print_b, NULL);

    /* At this point, two threads are all waiting to be woken up.
     * We let main send a signal and wake up thread_a to run first */
    pthread_mutex_lock(&mutex_a);
    pthread_cond_signal(&cond_a);
    is_round_of_a = true;
    pthread_mutex_unlock(&mutex_a);

    /* Waiting for two threads to complete.
     * Actually we will never reach here since two threads are all
     * executing in an infinite loop. */
    pthread_join(tid_a, NULL);
    pthread_join(tid_b, NULL);

    return 0;
}

Compile and Run

$ gcc ab.c -lpthread
$ ./a.out
a
b
a
b
a
b
a
...

References

[1] http://stackoverflow.com/questions/16522858/understanding-of-pthread-cond-wait-and-pthread-cond-signal
[2] http://linux.die.net/man/3/pthread_cond_wait
[3] http://www.ibm.com/developerworks/library/l-posix1
[4] http://www.ibm.com/developerworks/library/l-posix2
[5] http://www.ibm.com/developerworks/library/l-posix3