Как использовать очередь с двумя потоками, один для потребителя и один для производителя

Я использую приложение, в котором приложение более низкого уровня всегда вызывает обратный вызов RecData(char *buf) при получении данных.

В обратном вызове я создаю два потока и передаю функции потребителя и производителя этим созданным потокам соответственно.

Мой код:

void RecData (char * buf) {

CreateThread(NULL,0,producer_queue,(void *)buf,0,NULL);
CreateThread(NULL,0,consumer_queue,NULL,0,NULL);

}

Вышеприведенное работает, когда я получаю данные по одному за раз. Если я получу, скажем, 5 данных почти одновременно, то производитель_очереди должен сначала поместить все данные в очередь, а затем потребитель_очередь должен начать извлекать данные, но здесь, как только производитель_очередь помещает первые данные в очередь, потребитель_очередь извлекает их.


person Community    schedule 13.03.2009    source источник
comment
Есть ли причина, по которой вы создаете 2 потока каждый раз, когда получаете данные?   -  person Alan    schedule 13.03.2009
comment
НЕТ, мой единственный мотив - поставить данные в очередь, а затем прочитать данные из очереди, но если я просто помещу один поток для производителя в функцию RecData (char * buf), то как и когда я начну читать данные из очереди. пожалуйста помоги   -  person    schedule 13.03.2009
comment
Другой подход может заключаться в создании одного потока чтения. В обратном вызове RecCall вы просто заблокируете очередь и поставите в очередь данные. Ваш поток Reader будет зацикливаться на чтении данных из очереди. Просто мысль.   -  person Alan    schedule 13.03.2009
comment
Можете ли вы сказать мне, как мне это закодировать .. пожалуйста, добавьте несколько строк кода, чтобы сделать это   -  person    schedule 13.03.2009


Ответы (2)


То, что вы хотите сделать, я полагаю, это контролировать доступ к очереди. Вы захотите рассмотреть использование мьютекса для управления чтением из очереди.

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

При чтении из очереди вы увидите, заблокирован ли мьютекс. Если вы записываете данные в очередь, вы не сможете начать чтение, пока ваш поток-производитель не завершит запись всех своих данных и не освободит блокировку. Если вы на самом деле заблокируете мьютекс, вы предотвратите запись вашего потока записи, пока вы читаете данные.

Такой подход может привести к возникновению взаимоблокировок. Если ваш поток записи умирает до снятия блокировки, тогда ваш поток чтения не сможет продолжить работу (тогда снова умирание вашего потока может просто вызвать состояние ошибки).

Я надеюсь в этом есть смысл.

person Alan    schedule 13.03.2009
comment
Привет, Алан! Что на самом деле происходит с приведенным выше кодом, который я упоминал в своих вопросах, так это то, что поток для производителя и поток для потребителя всегда создаются один за другим. - person ; 13.03.2009
comment
Скажем, если обратный вызов RecData (char * buf) получает 5 данных почти одновременно, то для записи 1-го данных в очередь он создает поток для производителя, который записывает его в очередь, а затем создает еще один поток (потребитель) для прочитайте данные, и то же самое произойдет и со следующими данными. - person ; 13.03.2009
comment
Я хочу, чтобы он вел себя так, как когда он получает 5 данных, производитель должен записать все 5 данных в очередь, а затем потребительский поток должен начать читать эти 5 данных из очереди. Является ли это возможным? Спасибо - person ; 13.03.2009
comment
Вы говорите, что RedData вызывается 5 раз? - person Alan; 13.03.2009
comment
да .. точно .. каждый раз, когда запись данных в очередь вызывается для чтения данных next Consumer_queue .. - person ; 13.03.2009
comment
Знаете ли вы заранее, сколько элементов данных следует ожидать? Кроме того, почему вы хотите поставить в очередь все 5 элементов перед их чтением? Почему вы можете ставить в очередь и исключать из очереди независимо друг от друга? - person Alan; 13.03.2009
comment
Нет, я не знаю, сколько элементов данных я собираюсь ожидать ... также я хочу сделать очередь и удаление из очереди независимыми ... но как это сделать ... Скажем, если я просто поставлю только поток очереди, тогда он поставит в очередь все данные ... но тогда откуда я буду вызывать поток dequeu ..? - person ; 13.03.2009
comment
Вы можете создать очередь в любое время. Поток удаления из очереди может зацикливаться, проверяя очередь на наличие данных. - person Alan; 13.03.2009

Используйте концепцию условных переменных. Проблема, с которой вы столкнулись, является самой распространенной в мире многопоточного программирования. Просто использование мьютексов не помогает ситуации. Всегда помните, что мьютексы предназначены для блокировки, а условные переменные — для ожидания. Последнее всегда безопаснее и почти наверняка, когда поток должен начать потреблять из общей очереди.

Ознакомьтесь с приведенной ниже ссылкой, чтобы узнать, как самостоятельно создать переменную условия в Windows: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html

Если вы используете Windows Vista, приведенный ниже пример msdn может вам помочь: http://msdn.microsoft.com/en-us/library/ms686903(VS.85).aspx

Во всех случаях используйте логику, показанную на веб-сайте Шмидта, так как она выглядит более переносимой (по крайней мере, переносимой на разные версии Windows). Реализация Шмидта дает вам ощущение стандартного API POSIX, который является широко используемым стандартом в большинстве современных систем UNIX/LINUX.

person techcraver    schedule 13.03.2009
comment
Ваша ссылка msdn немного не работает. - person Simon Buchan; 13.03.2009