Скажем, у нас есть очередь без блокировки с одним потоком-производителем и без блокировки с потоком-потребителем, и что производитель может работать долго, не производя никаких данных.Было бы полезно оставить потребительский поток спящим, когда в очереди ничего нет (для экономии энергии и освобождения ЦП для других процессов / потоков).Если очередь не была без блокировки, простой способ решить эту проблему - заставить производящий поток блокировать мьютекс, выполнять свою работу, сигнализировать переменную условия и разблокировать, а поток чтения должен заблокировать мьютекс, подождать переменную условияПрочти, затем разблокируй.Но если мы используем очередь без блокировки, то использование мьютекса точно таким же образом уменьшит производительность, которую мы получаем в первую очередь от использования очереди без блокировки.
Наивное решение - иметь производителя после каждой вставкив очередь блокирует мьютекс, сигнализирует переменную условия, затем разблокирует мьютекс, сохраняя фактическую работу (вставку в очередь) полностью за пределами блокировки, и чтобы потребитель делал то же самое, блокируя мьютекс, ожидая условияпеременная, разблокируя ее, вытаскивая все из очереди, затем повторяя, сохраняя чтение очереди за пределами блокировки.Однако здесь есть условие гонки: между читателем, срывающим очередь и засыпающим, продюсер мог вставить элемент в очередь.Теперь читатель перейдет в спящий режим и может оставаться так до бесконечности, пока производитель не вставит другой элемент и снова не сообщит переменную условия.Это означает, что вы можете иногда сталкиваться с определенными предметами, которые, по-видимому, занимают очень много времени, чтобы пройти через очередь.Если ваша очередь всегда постоянно активна, это не может быть проблемой, но если бы она всегда была активной, вы, вероятно, могли бы полностью забыть переменную условия.
AFAICT, решение для производителя - вести себя так же, как если бы это былоработа с обычной очередью блокировки потребностей.Он должен блокировать мьютекс, вставлять в очередь без блокировки, сигнализировать переменную условия, разблокировать.Однако потребитель должен вести себя по-другому.Когда он проснется, он должен немедленно разблокировать мьютекс, а не ждать, пока он прочитает очередь.Затем он должен вытянуть как можно большую часть очереди и обработать ее.Наконец, только когда потребитель думает о том, чтобы идти спать, он должен заблокировать мьютекс, проверить, есть ли какие-либо данные, затем, если это так, разблокировать и обработать их, или, если нет, то подождать переменную условия.Таким образом, мьютекс утверждается реже, чем в случае блокировки очереди, но нет риска засыпать с данными, оставшимися в очереди.
Это лучший способ сделать это?Есть ли альтернативы?
Примечание : под «быстрым» я действительно подразумеваю «самый быстрый», не выделяя ядра для проверки очереди снова и снова », но это не вписывается в название;p
Одна альтернатива : используйте наивное решение, но потребителю придется ждать переменную условия с тайм-аутом, соответствующим максимальной задержке, которую вы готовы допустить для элемента, проходящего черезочередь.Если желаемое время ожидания довольно короткое, оно может быть ниже минимального времени ожидания для вашей ОС или по-прежнему потреблять слишком много ЦП.