2

In the code below:

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mtx;
pthread_cond_t cond;

int how_many = 10;
int pool = 0;

void * producer(void * ptr)
{
        while (how_many > 0)
        {
                pthread_mutex_lock(&mtx);
                printf("producer: %d\n", how_many);
                pool = how_many;
                how_many--;
                pthread_mutex_unlock(&mtx);
                pthread_cond_signal(&cond);
        }

        pthread_exit(0);
}

void * consumer(void * ptr)
{
        while (how_many > 0)
        {
                pthread_mutex_lock(&mtx);
                pthread_cond_wait(&cond, &mtx);
                printf("consumer: %d\n", pool);
                pool = 0;
                pthread_mutex_unlock(&mtx);
        }
        pthread_exit(0);
}

int main(int argc, char ** argv)
{
        pthread_t prod, cons;
        pthread_mutex_init(&mtx, 0);
        pthread_cond_init(&cond, 0);
        pthread_create(&cons, 0, consumer, 0);
        pthread_create(&prod, 0, producer, 0);
        pthread_join(prod, 0);
        pthread_join(cons, 0);
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mtx);
        return 0;
}

I'm not getting the expected output.

Expected output:

Producer:10    
Consumer:10    
Producer:9    
Consumer:9    
Producer:8    
Consumer:8    
Producer:7    
Consumer:7    
Producer:6    
Consumer:6    
Producer:5    
Consumer:5    
Producer:4    
Consumer:4    
Producer:3    
Consumer:3    
Producer:2    
Consumer:2    
Producer:1    
Consumer:1

Actual output:

producer: 10    
producer: 9    
producer: 8    
producer: 7    
producer: 6    
producer: 5    
producer: 4    
producer: 3    
producer: 2    
producer: 1

Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?

  1. Will it be dead lock?
  2. My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. Is that true?
3
  • You want to signal the condition from inside the critical section, that is before unlocking the related mutex. Commented May 26, 2015 at 13:41
  • "My friends are suggesting like ... is that true?" as per the documentation, it is, yes. Commented May 26, 2015 at 13:44
  • I used sleep(1) after releasing the lock at producer side it works fine:-) and i understood pthread_cond_wait() doesn't hold the lock until it gets the signal. Commented May 27, 2015 at 5:28

3 Answers 3

3

Mutexes provide only mutual exclusion (when used properly); they do not themselves provide a mechanism for blocking on a specific event to happen or until a specific condition is satisfied. That's what condition variables are for (and semaphores, if you want to go a little lower-level).

Your code provides for the consumer to wait on the producer to produce, but not for the producer to wait on the consumer to consume before it continues. If you want the two threads to alternate, then you need a second condition variable to provide for the latter.

Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?

  1. will it be dead lock?

  2. My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. is that true?

Rather than asking your friends -- or the Internet -- have you considered reading the documentation? Here's the way the man page describes it:

These functions atomically release mutex [...]. Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.

That is, the thread calling pthread_cond_wait() does not hold the mutex locked while it is waiting, but it reacquires the mutex before it returns (which may involve an indeterminate delay between the thread receiving the signal and the function call returning).

Additionally, always remember that a thread can wake up spurriously from waiting on a condition variable. It is essential to check upon wakeup whether the condition is in fact satisfied, and to resume waiting if not.

Here's a way you could structure the producer:

void * producer(void * ptr)
{
        pthread_mutex_lock(&mtx);
        while (how_many > 0)
        {
                if (pool == 0) {
                        printf("producer: %d\n", how_many);
                        pool = how_many;
                        how_many--;
                        pthread_cond_signal(&full_cond);
                }
                pthread_cond_wait(&empty_cond, &mtx);
        }
        pthread_mutex_unlock(&mtx);

        pthread_exit(0);
}

Note that:

  1. I have renamed your original condition variable and introduced a new one. There is now full_cond, indicating that the pool (of capacity 1) is full, and empty_cond, indicating that the pool is empty.
  2. The whole loop is protected by a mutex. This is fine because it performs a pthread_cond_wait() naming that mutex; the other threads will be able to run while the the producer is waiting. The mutex ensures that access to the how_many and pool variables is correctly synchronized.
  3. The loop protects against spurrious wakeup by testing pool to verify that it really is empty. If not, it loops back to the wait without doing anything else.
  4. For this to work correctly, the consumer requires corresponding changes (left as an exercise for you).
Sign up to request clarification or add additional context in comments.

1 Comment

I understood that pthread_cond_wait() doesn't holds the lock until it returns true :-)
2

You are checking how_many out of the locked section. You need to restructure you code so that reading the variable is covered by a lock or so that it is C11 _Atomic.

Even then, your code's output is likely not going to be the way you want it as the scheduling of the threads is pretty much unpredictable.

Comments

0

For your expected output you can use the locking mechanism like below,

 #include <pthread.h> 
 #include <stdio.h> 
 #include <stdlib.h> 
 #include <semaphore.h> 

 sem_t mutex1; 
 sem_t mutex2; 
 int main()
 {
    pthread_t thread1, thread2; 
    sem_init(&mutex1, 0, 1); 
    sem_init(&mutex2, 0, 0);
    pthread_create( &thread1, NULL, &producer, NULL)
    pthread_create( &thread2, NULL, &consumer, NULL)
    pthread_join( thread1, NULL); 
    pthread_join( thread2, NULL); 
    return 0; 
 }


void producer()
{
  sem_wait(&mutex1); 
  :
  :

  sem_post(&mutex2);
}

void consumer ()
{
    sem_wait(&mutex2); 
    :
    : 
    sem_post(&mutex1);
}   

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.