pthread_cond_wait for 2 threads

c, linux, pthreads

Solution

You have two problems. The first is that you aren't using `while()` loops correctly - for example, here:

//wait for turn
while( pthread_cond_wait(&condA, &mutex) != 0 )

i++;

The body of the `while` loop is the statement `i++` - this will execute `pthread_cond_wait()` and `i++` until the `pthread_cond_wait()` returns an error, so this is essentially an endless loop.

The second is that you can't use a pthreads condition variable on its own - it needs to be paired with some actual shared state (at its simplest, this shared state might just be a flag variable protected by a mutex). The `pthread_cond_wait()` function is used to wait for the shared state to reach a certain value, and the `pthread_cond_signal()` function is used when a thread has altered the shared state. Reworking your example to use such a variable:

//global variables
/* STATE_A = THREAD A runs next, STATE_B = THREAD B runs next */
enum { STATE_A, STATE_B } state = STATE_A;
pthread_cond_t      condA  = PTHREAD_COND_INITIALIZER;
pthread_cond_t      condB  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;

void *threadA()
{
    int i = 0, rValue, loopNum;

    while(i<5)
    {
        /* Wait for state A */
        pthread_mutex_lock(&mutex);
        while (state != STATE_A)
            pthread_cond_wait(&condA, &mutex);
        pthread_mutex_unlock(&mutex);

        //do stuff
        for(loopNum = 1; loopNum <= 5; loopNum++)
            printf("Hello %d\n", loopNum);

        /* Set state to B and wake up thread B */
        pthread_mutex_lock(&mutex);
        state = STATE_B;
        pthread_cond_signal(&condB);
        pthread_mutex_unlock(&mutex);

        i++;
    }

    return 0;
}

void *threadB()
{
    int n = 0, rValue;

    while(n<5)
    {
        /* Wait for state B */
        pthread_mutex_lock(&mutex);
        while (state != STATE_B)
            pthread_cond_wait(&condB, &mutex);
        pthread_mutex_unlock(&mutex);

        //do stuff
        printf("Goodbye\n");

        /* Set state to A and wake up thread A */
        pthread_mutex_lock(&mutex);
        state = STATE_A;
        pthread_cond_signal(&condA);
        pthread_mutex_unlock(&mutex);

        n++;
    }

    return 0;
}

Note that the use of two condition variables `condA` and `condB` is unnecessary here - the code would be just as correct if only one condition variable was used instead.

Problem

I'm trying to implement `pthread_cond_wait` for 2 threads. My test code is trying to use two threads to preform the following scenario: - Thread B waits for condition - Thread A prints "Hello" five times - Thread A signals thread B - Thread A waits - Thread B prints "Goodbye" - Thread B signals thread A - Loop to start (x5) So far the code prints "Hello" five times and then gets stuck. From examples I've looked at it seems I'm on the right track, "Lock mutex, wait, get signaled by other thread, unlock mutex, do stuff, loop" Test Code: ``` //Import #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> //global variables pthread_cond_t condA = PTHREAD_COND_INITIALIZER; pthread_cond_t condB = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *threadA() { int i = 0, rValue, loopNum; while(i<5) { //unlock mutex rValue = pthread_mutex_unlock(&mutex); //do stuff for(loopNum = 1; loopNum <= 5; loopNum++) printf("Hello %d\n", loopNum); //signal condition of thread b rValue = pthread_cond_signal(&condB); //lock mutex rValue = pthread_mutex_lock(&mutex); //wait for turn while( pthread_cond_wait(&condA, &mutex) != 0 ) i++; } } void *threadB() { int n = 0, rValue; while(n<5) { //lock mutex rValue = pthread_mutex_lock(&mutex); //wait for turn while( pthread_cond_wait(&condB, &mutex) != 0 ) //unlock mutex rValue = pthread_mutex_unlock(&mutex); //do stuff printf("Goodbye"); //signal condition a rValue = pthread_cond_signal(&condA); n++; } } int main(int argc, char *argv[]) { //create our threads pthread_t a, b; pthread_create(&a, NULL, threadA, NULL); pthread_create(&b, NULL, threadB, NULL); pthread_join(a, NULL); pthread_join(b,NULL); } ``` A pointer in the right direction would be greatly appreciated, thanks! (Code compiled on Linux using "gcc timeTest.c -o timeTest -lpthread")

Original source