Хотя другие уже правильно проанализировали проблему (насколько я могу судить), позвольте мне попытаться добавить некоторые подробности к предлагаемым решениям.
Во-первых, суммируем проблемы: 1. ЕслиВы заставляете свой потребительский поток работать в цикле for или подобном, это ужасная трата мощности процессора.2. Если вы используете функцию sleep () с фиксированным числом миллисекунд, это либо пустая трата ЦП (либо слишком мало времени), либо вы излишне задерживаете процесс (если он слишком велик).Невозможно правильно установить количество времени.
Вместо этого вам нужно использовать тип сна, который просыпается в нужный момент, то есть всякий раз, когда новыйзадача была добавлена в очередь.
Я объясню, как это сделать с помощью POSIX.Я понимаю, что это не идеально, когда вы работаете в Windows, но для этого вы можете использовать библиотеки POSIX для Windows или использовать соответствующие функции, доступные в вашей среде.
Шаг 1: Вам нужен один мьютекс и один сигнал:
#include <pthread.h>
pthread_mutex_t *mutex = new pthread_mutex_t;
pthread_cond_t *signal = new pthread_cond_t;
/* Initialize the mutex and the signal as below.
Both functions return an error code. If that
is not zero, you need to react to it. I will
skip the details of this. */
pthread_mutex_init(mutex,0);
pthread_cond_init(signal,0);
Шаг 2: Теперь внутри потока потребителя дождитесь отправки сигнала.Идея состоит в том, что производитель отправляет сигнал всякий раз, когда он добавляет новое задание в очередь:
/* Lock the mutex. Again, this might return an error code. */
pthread_mutex_lock(mutex);
/* Wait for the signal. This unlocks the mutex and then 'immediately'
falls asleep. So this is what replaces the busy spinning, or the
fixed-time sleep. */
pthread_cond_wait(signal,mutex);
/* The program will reach this point only when a signal has been sent.
In that case the above waiting function will have locked the mutex
right away. We need to unlock it, so another thread (consumer or
producer alike) can access the signal if needed. */
pthread_mutex_unlock(mutex);
/* Next, pick a task from the queue and deal with it. */
Шаг 2, описанный выше, по существу должен быть помещен в бесконечный цикл.Убедитесь, что есть способ вырваться из цикла.Например, хотя и немного грубовато, вы можете добавить в очередь «специальную» задачу, которая означает «вырваться из цикла».
Шаг 3: Включить поток производителя вотправлять сигнал всякий раз, когда он добавляет задачу в очередь:
/* We assume we are now in the producer thread and have just appended
a task to the queue. */
/* First we lock the mutex. This must be THE SAME mutex object as used
in the consumer thread. */
pthread_mutex_lock(mutex);
/* Then send the signal. The argument must also refer to THE SAME
signal object as is used by the consumer. */
pthread_cond_signal(signal);
/* Unlock the mutex so other threads (producers or consumers alike) can
make use of the signal. */
pthread_mutex_unlock(mutex);
Шаг 4: Когда все закончится и вы закроете свои потоки, вы должны уничтожить мьютекс и сигнал:
pthread_mutex_destroy(mutex);
pthread_cond_destroy(signal);
delete mutex;
delete signal;
В заключение позвольте мне еще раз повторить одно, что уже говорили другие: вы не должны использовать обычный std::deque
для одновременного доступа.Один из способов решения этой проблемы - объявить еще один мьютекс, заблокировать его перед каждым доступом к deque и разблокировать сразу после него.
Редактировать: еще несколько слов о потоке производителя ,в свете комментариев.Насколько я понимаю, поток продюсера в настоящее время может добавлять в очередь столько задач, сколько может.Поэтому я полагаю, что он продолжит делать это и будет загружать процессор до такой степени, чтобы он не задерживался из-за ввода-вывода и доступа к памяти.Во-первых, я не думаю, что высокая загрузка ЦП, вызванная этим, является проблемой, а скорее преимуществом.Однако одна серьезная проблема заключается в том, что очередь будет расти бесконечно, что может привести к тому, что процессу не хватит места в памяти.Следовательно, полезная мера предосторожности заключается в том, чтобы ограничить размер очереди до разумного максимума и заставить поток производителя делать паузу всякий раз, когда очередь становится слишком длинной.
Для реализации этого поток производителя будет проверять длинуочереди перед добавлением нового элемента.Если он заполнен, он переводит себя в спящий режим, ожидая, пока потребитель не отправит сигнал при удалении задачи из очереди.Для этого вы можете использовать вторичный сигнальный механизм, аналогичный описанному выше.