Shulan TANG Shulan TANG - 9 days ago 5
C Question

Deadlock in producer-consumer C programming

I am trying to implement a single-producer-multi-consumer program in C, and I'm using the character '\0' in consumer to see whether it is the end of the file. However, deadlock occurs when when there are multi-consumer and when they all waiting for last character but only one of them entered critical section and consume this character. Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#define BUFFER_SIZE 10
#define NUM_OF_INTEGERS 20
#define NUM_OF_CONSUMER 3
sem_t empty;
sem_t full;
sem_t mutex;
char *buffer;
int in = 0;
int out = 0;
void insert(char* buffer, char value){
printf("lock in insert %c\n", value);
sem_wait(&empty);
sem_wait(&mutex);
printf("insert %c\n",value);
buffer[in] = value;
in = (in+1) % NUM_OF_INTEGERS;
sem_post(&mutex);
sem_post(&full);
}
char get(char* buffer) {
char item;
printf("lock in get\n");

sem_wait(&full);
sem_wait(&mutex);
item = buffer[out];
printf("comsume %c\n",item);
out = (out+1)%NUM_OF_INTEGERS;
sem_post(&mutex);
sem_post(&empty);
return item;
}
void *produce(void *param) {
int i=0;
char randomChar;
for(i=0; i<NUM_OF_INTEGERS; ++i) {
randomChar = 'A' +random()%26;
insert(buffer, randomChar);
}
insert(buffer, '\0');
printf("produce finished\n");
}

void *consume(void *param) {
int i=0;
char data;
do{
data = get(buffer);
}while(data != '\0');
printf("consume finished\n");
}

int main() {
buffer = (char*) malloc(sizeof(char)*BUFFER_SIZE);
pthread_t consumer[NUM_OF_CONSUMER];
pthread_t producer;
int i;
sem_init(&full,0,0); // full buffer
sem_init(&empty,0,BUFFER_SIZE); //empty buffer
sem_init(&mutex,0,1);

pthread_create(&producer, 0, produce, 0);
for(i = 0; i < NUM_OF_CONSUMER; i++) {
pthread_create(&consumer[i], 0, consume, 0);
}
printf("finished\n");
pthread_join(producer, 0);
for(i = 0; i < NUM_OF_CONSUMER; i++) {
pthread_join(consumer[i], 0);
}

sem_destroy(&full);
sem_destroy(&empty);
sem_destroy(&mutex);

return 0;
}

Answer

As others have mentioned, you need to send more than one terminator (i.e.) one for each consumer.

In produce, change:

insert(buffer, '\0');

Into:

for (i=0; i<NUM_OF_CONSUMER; ++i)
    insert(buffer, '\0');
Comments