2
votes

I am fairly new to pthread programming and am trying to get my head around cond_signal & mutex_lock. I am writing a sample program which has One producer thread and Two consumer threads.

There is a queue between producer and the first consumer and a different queue between producer and the second consumer. My producer is basically a communication interface which reads packets from the network and based on a configured filter delivers the packets to either of the consumers.

I am trying to use pthread_cond_signal & pthread_mutex_lock the following way between producer and consumer.

[At producer]

0) Wait for packets to arrive

1) Lock the mutex pthread_mutex_lock(&cons1Mux)

2) Add the packet to the tail of the consumer queue

3) Signal the Consumer 1 process pthread_cond_signal(&msgForCons1)

4) Unlock the mutex pthread_mutex_lock(&cons1Mux)

5) Go to step 0

[At consumer]

1) Lock the mutex pthread_mutex_lock(&cons1Mux)

2) Wait for signal pthread_cond_wait(&msgForCons1,&cons1Mux)

3) After waking up, read the packet

4) Delete from queue.

5) Unlock the mutex pthread_mutex_unlock(&cons1Mux)

6) Goto Step 1

Are the above steps correct? If a switch happens from the consumer thread exactly after step 5 to the producer thread, then is it possible that the producer may signal a packet is waiting even though the consumer hasn't yet started listening for that signal. Will that cause a "missed signal"?

Are there any other problems with these steps?

1

1 Answers

2
votes

Yes, you're correct you could have a problem there: if there are no threads waiting, the pthread_cond_signal is a no-op. It isn't queued up somewhere to trigger a subsequent wait.

What's you're supposed to do is, in the consumer, once you've acquired the mutex, test whether there is any work to do. If there is, well, you have a mutex; take ownership, update state, and do it. You only need to wait if there is nothing to do.

The cannonical example is:

decrement_count() 
   { pthread_mutex_lock(&count_lock); 

     while (count == 0) 
        pthread_cond_wait(&count_nonzero, &count_lock); 
     count = count - 1; 
     pthread_mutex_unlock(&count_lock); 
   } 

increment_count() 
   { pthread_mutex_lock(&count_lock); 
     if (count == 0)
       pthread_cond_signal(&count_nonzero); 
     count = count + 1;
     pthread_mutex_unlock(&count_lock); 
    }

Note how the "consumer" decrementing thread doesn't wait around if there's something to decrement. The pattern applies equally well to the case where count is replaced by a queue size or the validity of a struct containing a message.