2016-05-08 2 views
0

У меня есть университетское задание, где я должен использовать потоки для выполнения некоторых вычислений. Это сводится к одному потребителю с несколькими производителями -> каждый производитель делает один расчет, потребитель добавляет все это вместе.C - Pthreads, один потребитель, синхронизация нескольких производителей

У меня возникли проблемы с синхронизацией этого, чтобы производитель перешел в его критическую секцию всякий раз, когда потребитель вычислил свою часть и вышел из своей критической секции.

Вот код, который я до сих пор:

ПОТРЕБИТЕЛЕЙ

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*/ 

ПРОИЗВОДИТЕЛЬ - Каждый производитель производит только одно значение (обязательно - задание)

pthread_mutex_lock(&mutex); 

    /*Do some stuff*/ 

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

Является ли это можно сделать это только с условиями и мьютексом? Если нет, я предполагаю, что добавление семафора упростит ситуацию, но я предпочел бы сделать это без него.

Каждый производитель должен поместить свой продукт в глобальную переменную, к которой должен обращаться потребитель.

Если есть что-то еще, сообщите мне.

РЕШЕНИЕ : После прочтения ответа Джон Боллинджер, я был в состоянии исправить мою проблему и создать рабочую проблему производитель/потребитель.

/******************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); 
+0

Если все дочерние (потребительские) потоки выполняются параллельно, а потоку родителя (производителя) просто нужно собирать свои результаты, он может просто «pthread_join» их по одному. Вероятно, это все равно. – Useless

+0

@ Безболезненно. Я сейчас посмотрю, спасибо, что указал мне в правильном направлении. – MichaelDawn

+0

@ Бездумно, я добавил немного информации в разделе «EDIT1», из-за того, как производитель должен получить доступ к результату, я не думаю, что могу использовать pthread_join? – MichaelDawn

ответ

1

Можно ли это сделать только с условиями и взаимной блокировки?

Предположим, что вы имеете в виду без использования каких-либо других объектов синхронизации, в отличие от чего-либо вообще (например, переменных), да, это возможно. Вы можете сделать это с помощью одной переменной mutex и одного условия, или в этом случае вы можете использовать два CV - один для потребителя, а другой для всех производителей.

Никогда не забывайте, что правильное использование переменной условия всегда связано с ожиданием того, что какой-либо предикат станет истинным. Предикат является внешним по отношению к самому CV, и ответственность программиста - это проверить его. Стандартный шаблон для ожидания на переменном состоянии выглядит следующим образом:

  1. заблокировать мьютекс
  2. теста предикат
  3. если предикат истинно, то перейти к (6)
  4. ожидания на CV
  5. после возвращения из ожидания, перейдите к (2)
  6. [опционально] делать вещи под защитой мьютекса
  7. разблокировать мьютекс

Необходимо проверить предикат перед ожиданием, и его необходимо снова проверить (и, возможно, подождать) после возвращения из ожидания.

В вашем случае предикат для потоков производителей, на словах, «глобальная переменная для записи продукта доступна для меня». Предикат для потребительского потока - «есть продукт, доступный в глобальной переменной». В зависимости от характера и типа продуктов может потребоваться добавить вспомогательную переменную, с которой потоки могут сообщать состояние этих предикатов между собой.

Обратите внимание также, что, когда один поток в системе, подобный этому, завершает свою собственную работу, важно, чтобы этот поток соответствующим образом обновлял глобальное состояние и сигнализировал переменную условия, чтобы другие потоки получили возможность продолжить. Это может произойти как часть шага (6) выше, или поток может через некоторое время снова заблокировать мьютекс, чтобы обновить общее состояние и передать CV.

+0

thankyou, я смог выяснить, как это сделать благодаря вам. Я ценю не только предоставление мне кода, поэтому я могу понять, почему он работает. – MichaelDawn

Смежные вопросы