Kevin
Kevin

Reputation: 43

Reader threads not exiting - Posix Pthreads

I have to create a solution to the readers writers problem using posix pthreads, I have condensed my code down to pseudocode mixed with C to reduce the size of the code.

The writer thread finishes fine but the reader threads never terminate/exit so the Reader join is waiting forever, and the program hangs.

I believe it is related to the wait condition pthread_cond_wait(&qElement, &mutex); in the reader function. It may be waiting for a terminated writer thread to signal. I have tried encapsulating it with if(!finished) so it only waits if the writer is still active but that still hasn't worked.

I am not sure what to do and believe it as a logic error with my pthread handling.

Would really appreciate the help.

Global variables in header file : 

#define TRUE 1
#define FALSE 0

int finished = FALSE

pthread_cond_t qServiced = PTHREAD_COND_INITIALIZER;
pthread_cond_t qEmpty = PTHREAD_COND_INITIALIZER;
pthread_cond_t qElement = PTHREAD_COND_INITIALIZER;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int main()
{
    Create 1 writer thread
    Create 2 reader threads

    Writer join <- Success 
    Reader join <- Program hangs here


void* writer()
{
    int totalQueued = 0; 
    int tasks = 20; 

    while(!finished)
    {
        pthread_mutex_lock(&mutex); 

        while(isFull(q))
        {
            pthread_cond_wait(&qEmpty, &mutex); 
        }

        if(totalQueued < tasks)
        {
            for(j = 0; j < 2; j++) //Add 2 numbers at a time 
            {
                if(!(isFull(q)))
                {
                    //Assume random numbers added to queue 
                    totalQueued++;
                }
            }
            pthread_cond_signal(&qElement);
            pthread_cond_wait(&qServiced, &mutex);
        }
        else
        {
            finished = TRUE; 
        }
        pthread_mutex_unlock(&mutex); 
    } 

    //Thread exits
}

void* reader()
{
    while(!finished)
    {
        pthread_mutex_lock(&mutex);

        while(isEmpty(q)) //If the queue is empty 
        {
            pthread_cond_signal(&qEmpty);
            pthread_cond_wait(&qElement, &mutex);
        }

        int n = dequeue(q); 
        printf("%d\n", n); 

        pthread_cond_signal(&qServiced); //Signal that task has been serviced
        pthread_mutex_unlock(&mutex);
    }
}

Upvotes: 0

Views: 93

Answers (1)

John Bollinger
John Bollinger

Reputation: 180286

You having presented only a sketch of your code, I am unable to perform a complete analysis, but even the sketch shows a deficiency in your approach. When the writer makes new data available it unblocks one reader:

            pthread_cond_signal(&qElement);

If both readers are waiting when the writer posts the last pieces of work (which appears likely), then one will be left waiting when the writer terminates.

The best solutions revolve around using pthread_cond_broadcast() instead of or in addition to pthread_cond_signal(). It should be fine to just substitute the latter for the former, since your readers ought to be protecting themselves against spurious wakeups anyway (and it looks like they indeed are). If you prefer, though, you can have the writer broadcast just before it terminates, or have the main thread broadcast after it joins the writer.

Additionally, I'm inclined to think that you're using a lot more CVs than you actually need. Very likely you can use just one, which will be simpler both to write and to reason about.

Upvotes: 1

Related Questions