简体   繁体   中英

C - Pthreads, one consumer, multiple producers synchronisation

I have a university assignment where I have to use threads to do some calculations. It boils down to one consumer with multiple producers --> each producer does one calculation, consumer adds it all together.

I'm having trouble synchronising this so that the producer will go into its critical section whenever a consumer has calculated their part and exited their critical section.

Here's the code I have so far:

CONSUMER

do
{
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&consumer, &mutex);

        /*Do some stuff*/

    pthread_mutex_unlock(&mutex);
    count++;
} while(count < m); /*Where m is the number of producers*/

PRODUCER - Each producer only produces one value (Required - Assignment)

pthread_mutex_lock(&mutex);

    /*Do some stuff*/

pthread_cond_signal(&consumer);
pthread_mutex_unlock(&mutex);

Is it possible to do this with only conditions and the mutex? If not, I'm assuming adding a semaphore would make things easier, but I'd rather try do it without.

Each producer must place their product into a global variable which must then be accessed by the consumer.

If there's anything else required, let me know.

SOLUTION : After reading John Bollinger's reply, I was able to fix my issue and create a working producer/consumer problem.

/******************CONSUMER*****************/
pthread_mutex_lock(&mutex);
while(count < m) /*While there are more threads*/
{
    /*Makes producers wait for the consumer to be ready before
    altering the global variable*/
    if( predicate = -1 )
    {
        predicate = 0;
        pthread_cond_signal(&producer);
    }
    /*Make consumer wait for the global variable to be altered*/
    while(predicate == 0)
        pthread_cond_wait(&consumer, &mutex);

      /*Do some stuff with global variable*/
      predicate = 0; /*Consumed*/

    count++;
    /*Tell a producer that the predicate has been consumed*/
    pthread_cond_signal(&producer);
}
pthread_mutex_unlock(&mutex);


/********************PRODUCER********************/
pthread_mutex_lock(&mutex);

/*If the consumer is not ready yet, wait. I.e. if it's still
  creating more threads*/
if(predicate == -1)
{
    pthread_cond_wait(&producer, &mutex);
}

/*If there is already a product to be consumed, wait until
 *consumed*/
while( predicate != 0 )
{
    pthread_cond_wait(&producer, &mutex);
}

    /*Do some stuff with global variable*/

/*Tell consumer that a product is ready to be consumed*/
pthread_cond_signal(&consumer);
pthread_mutex_unlock(&mutex);

Is it possible to do this with only conditions and the mutex?

Supposing that you mean without using any other synchronization objects, as opposed to without anything else at all (eg variables), yes, it is possible. You can do it with one mutex and one condition variable, or in this case you might consider using two CVs -- one for the consumer and another for all of the producers.

Never forget that the proper use of a condition variable always involves waiting for some predicate to become true. The predicate is external to the CV itself, and it is the programmer's responsibility to test it. The standard pattern for waiting on a condition variable goes like this:

  1. lock the mutex
  2. test the predicate
  3. if the predicate is true then go to (6)
  4. wait on the CV
  5. upon returning from the wait, go to (2)
  6. [optional] do stuff under protection of the mutex
  7. unlock the mutex

It is necessary to test the predicate before waiting, and it is necessary to test it again (and maybe wait again) after returning from the wait.

In your case the predicate for the producer threads is, in words, "the global variable for recording a product is available for me to use". The predicate for the consumer thread is "there is a product available in the global variable". Depending on the nature and type of the products, it might be necessary to add an auxiliary variable with which the threads can communicate the state of those predicates among themselves.

Note also that when one thread in system like this finishes its own piece of work, it is essential for that thread to update the global state appropriately and to signal the condition variable, so that other threads get a chance to proceed. That might happen as part of step (6) above, or the thread might some time later lock the mutex again, so as to update the shared state and signal the CV.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM