Question

This is the code I have:

int BufferSize = 3;
int buffer[3] = {0,0,0};

int producer_cursor = 0;
int consumer_cursor = 0;

sem_t empty, mutex, full;

void* Producer(void *arg)
{

    sem_wait(&empty);
    sem_wait(&mutex);

    printf("producer thread: #%d in critical setion\n", *((int*) arg));
    int j;
    for (j=0;j<BufferSize;j++) {
        printf("%d", buffer[j]);
    }
    printf("\n");
    buffer[producer_cursor] = 1;
    producer_cursor = (++producer_cursor) % 3;

    for (j=0;j<BufferSize;j++) {
        printf("%d", buffer[j]);
    }
    printf("\n");
    sem_post(&full);
    sem_post(&mutex);
}

void * Consumer(void* arg)
{
   sem_wait(&full);
   sem_wait(&mutex);    

   printf("consumer thread: #%d in critical setion\n", *((int*) arg));
   int j;
   for (j=0;j<BufferSize;j++) {
      printf("%d", buffer[j]);
   }
   printf("\n");

   buffer[consumer_cursor] = 0;
   consumer_cursor = (++consumer_cursor) % 3;
   printf("after change\n");
   for (j=0;j<BufferSize;j++) {
       printf("%d", buffer[j]);
   }
   printf("\n");

   sem_post(&empty);
   sem_post(&mutex);
}

void main(int argc, char * argv[])
{
   int n; 
   pthread_t *threads;

   sem_init(&mutex, 0, 1);
   sem_init(&empty, 0, 3);
   sem_init(&full, 0, 0);   

   pthread_t consumers[NUM_COMSUMERS];
   pthread_t producers[NUM_PRODUCERS];

   int i;
   for (i = 0; i < NUM_COMSUMERS; i++) {
       pthread_create(consumers+i, NULL, Consumer, &i);
   }
   for (i = 0; i < NUM_PRODUCERS; i++) {
       pthread_create(producers+i, NULL, Producer, &i);
   }
   for (i = 0; i < NUM_COMSUMERS; i++) {
       pthread_join(consumers[i], NULL);
   }
   for (i = 0; i < NUM_PRODUCERS; i++) {
       pthread_join(producers[i], NULL);
   }
}

And the output I get is:

producer thread: #1 in critical setion
000
100
consumer thread: #4 in critical setion
100
after change
000
producer thread: #0 in critical setion
000
010
consumer thread: #1 in critical setion
010
after change
000
producer thread: #1 in critical setion
000
001
producer thread: #2 in critical setion
001
101
consumer thread: #2 in critical setion
101
after change
100
consumer thread: #2 in critical setion
100
after change
000
producer thread: #2 in critical setion
000
010
consumer thread: #4 in critical setion
010
after change
000

The results are expected except that, the count should be ranging from 0 to 4, while it does not have "#3" in this case. And the "#" changes every time when I run the program. Sometimes it is even only showing "#0" and "#1".

Was it helpful?

Solution

The last argument to pthread_create is the issue. You pass a pointer to i, but the value of i changes as the main loop executes. There is no guarantee that i is still 0 (or 1 or 2 or 3) when your threads execute the print and you deference the pointer.

Try this simple change; it will give you the expected results:

int i;
int id[4] = { 1, 2, 3, 4 };
for (i = 0; i < NUM_COMSUMERS; i++) {
    pthread_create(consumers+i, NULL, Consumer, id + i);
}
for (i = 0; i < NUM_PRODUCERS; i++) {
    pthread_create(producers+i, NULL, Producer, id + i);
}

The above assumes NUM_CONSUMERS and NUM_PRODUCERS is 4, it will need reworked to make it more generic.

Alternatively, you don't necessary have to pass a pointer in, you could do the following:

for (i = 0; i < NUM_COMSUMERS; i++) {
    pthread_create(consumers+i, NULL, Consumer, (void *)i);
}
for (i = 0; i < NUM_PRODUCERS; i++) {
    pthread_create(producers+i, NULL, Producer, (void *)i);
}

And in your threads, don't dereference arg, just cast it to int:

printf("producer thread: #%d in critical section\n", (int)arg);

and:

printf("consumer thread: #%d in critical section\n", (int)arg);

NOTE: You will get warnings casting between a pointer and an int on 64-bit systems.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top