user1024718
user1024718

Reputation: 575

pthread synchronization on two consumers one producer

I have a worker thread processing a queue of work items.

//producer
void push_into_queue(char *item) {
    pthread_mutex_lock (&queueMutex);
    if(workQueue.full) { // full }
    else{
        add_item_into_queue(item);
        pthread_cond_signal (&queueSignalPush);
    }   
    pthread_mutex_unlock(&queueMutex);
}
// consumer1
void* worker(void* arg) {
    while(true) {
        pthread_mutex_lock(&queueMutex);
        while(workQueue.empty)
            pthread_cond_wait(&queueSignalPush, &queueMutex);

        item = workQueue.front; // pop from queue
        add_item_into_list(item);

        // do I need another signal here for thread2?
        pthread_cond_signal(&queueSignalPop);
        pthread_mutex_unlock(&queueMutex);
    }   
    return NULL;
}
pthread_create (&thread1, NULL, (void *) &worker, NULL);

Now I would like to have thread2 consume the data inserted in add_item_into_list() but only if items have been added to the list. Note that the list is permanent and can't be emptied nor freed for the entire duration of the program.

So my question is: do I need another pthread_cond_signal?, if yes, where would this signal go? and how my other worker would look like (canonical form)?

Upvotes: 1

Views: 322

Answers (1)

nogard
nogard

Reputation: 9706

I see 2 possible ways of solving the problem:

a. Introduce another condition variable (e.g. signalList) for the list, so that consumer2 thread would wait for events on it. In this case consumer1 have to signal twice: once on queueSignalPop and once on signalList:

// consumer1
void* worker(void* arg) {
    while(true) {
        // ...
        pthread_cond_signal(&queueSignalPop);
        pthread_cond_signal(&signalList);
        pthread_mutex_unlock(&queueMutex);
    }   
    return NULL;
}

b. Use existing condition queueSignalPop variable inside consumer2 to wait for events, and use broadcast instead of signal inside consumer1. Broadcast means all the waiting threads on condition variable will wake up:

// consumer1
void* worker(void* arg) {
    while(true) {
        // ...
        pthread_cond_broadcast(&queueSignalPop);
        pthread_mutex_unlock(&queueMutex);
    }   
    return NULL;
}
// consumer2
void* worker2(void* arg) {
    while(true) {
        while(list.empty)
            pthread_cond_wait(&queueSignalPop, &queueMutex);
        // ...
    }   
    return NULL;
}

I would propose to go for the first approach, since it better distinguish the purpose of each condition variable.

Upvotes: 1

Related Questions