0

With C's pthread library, I'm trying to implement a simple producer-consumer schema.

The producer generates random numbers and puts them into a queue like this

typedef struct {
    int q[MAX_QUEUE];
    int head;
    int tail;
} queue;

The consumer just takes numbers one by one and prints them to the standard output. Synchronisation is done with one mutex and two condition variables: empty_queue (to suspend the consumer if the queue is empty) and full_queue (to suspend the producer if the queue is full). The problem is that both threads suspend themselves when reaching MAX_QUEUEelements produced/consumed and so they enter a deadlock situation. I think I have done everything correct, I can't figure out what I'm doing wrong.

Producer:

void* producer(void* args) {
    unsigned seed = time(NULL);
    int random;
    queue *coda = (queue *) args;

    while(1) {
        Pthread_mutex_lock(&queue_lock);
        while(coda->head == MAX_QUEUE-1) { // Full Queue
            printf("Suspending producer\n");
            fflush(stdout);
            Pthread_cond_wait(&full_queue, &queue_lock);
        }

        random = rand_r(&seed) % 21;
        enqueue(coda, random);

        Pthread_cond_signal(&empty_queue);
        Pthread_mutex_unlock(&queue_lock);

        sleep(1);
    }

    return NULL;
}

Consumer:

void* consumer(void* args) {
    queue *coda = (queue *) args;
    int elem;

    while(1) {
        Pthread_mutex_lock(&queue_lock);
        while(coda->head == coda->tail) { // Empty Queue
            printf("Suspending Consumer\n");
            fflush(stdout);
            Pthread_cond_wait(&empty_queue, &queue_lock);
        }

        elem = dequeue(coda);
        printf("Found %i\n",elem);

        Pthread_cond_signal(&full_queue);
        Pthread_mutex_unlock(&queue_lock);
    }

    return NULL;
}

Enqueue/Dequeue routines

static void enqueue(queue *q, int elem) {
    q->q[(q->tail)] = elem;
    (q->tail)++;
    if(q->tail == MAX_QUEUE)
        q->tail = 0;
}

static int dequeue(queue *q) {
    int elem = q->q[(q->head)];
    (q->head)++;
    if(q->head == MAX_QUEUE)
        q->head = 0;
    return elem;
}

Pthread_* are just wrapper functions to the standard pthread_* library functions. Output (with MAX_QUEUE = 10):

Suspending Consumer
Found 16
Suspending Consumer
Found 7
Suspending Consumer
Found 5
Suspending Consumer
Found 6
Suspending Consumer
Found 17
Suspending Consumer
Found 1
Suspending Consumer
Found 12
Suspending Consumer
Found 14
Suspending Consumer
Found 11
Suspending Consumer
Suspending producer
Davide R.
  • 207
  • 2
  • 8

1 Answers1

0
coda->head == MAX_QUEUE-1

This does not check whether the queue is full. There are two variables that describe the state of the queue, head and tail.

coda->head == coda->tail

This properly checks that the queue is empty. Note how both variables are used in the check.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243