boost c++ lock-free queue vs общая очередь

Я довольно новичок в многопоточном программировании, я просто знаю наиболее распространенную очередь производитель-потребитель. Я использую библиотеки boost c++, и я не знаю, лучше ли использовать boost::lockfree::queue или класс-оболочку вокруг std::queue, который использует "мьютекс" и "condition_variable".

Где лучше использовать структуры данных без блокировки и где лучше использовать простую реализацию на основе "мьютекса" и "condition_variables"?

4 ответов


попробуйте оба в вашем приложении, посмотрите, что работает лучше всего.

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

недостатком блокирующих очередей является задержка, обычно порядка 2-20 uS, из-за сигнализации ядра. Это можно смягчить, разработав систему таким образом, чтобы работа, выполняемая потоками потребителя для каждого элемента очереди, занимала гораздо больше времени, чем это интервал.

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

Как уже намекали комментаторы, неблокирующая очередь-очень плохая идея для систем с одним процессором.


(дополнительный)

начиная с 1.54, вы должны знать о некоторых требованиях

boost::lockfree::queue

  • T должен иметь конструктор копирования
  • T должен иметь тривиальный оператор присваивания
  • T должен иметь тривиальный деструктор

boost::lockfree::stack

  • T должен иметь копию конструктор

boost::lockfree::spsc_queue

  • T должен иметь конструктор по умолчанию
  • T должен быть копируемым

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

например, OpenSL на Android предоставляет обратные вызовы очереди аудио буфера в высокоприоритетном потоке. Если этот поток должен ждать блокировок, удерживаемых потоком с более низким приоритетом, его высокоприоритетное планирование ничего не значит, обратные вызовы становятся нерегулярными, и вы можете начать переполнять свой звуковой буфер, что приводит к некоторым неприятным звукам.


решение сводится к тому, чтобы задать вопрос: "будет блокировок быть проблемой для задачи, которая должна быть решена?"

блокировка в параллельной среде решает две различные проблемы

  • корректность: убедитесь, что код действительно делает то, что предназначено. Предотвращение помех от других потоков.
  • объем / масштабируемость: позвольте, который вытерпели высокой "подаче" одновременных деятельностей проходя через систему. Позволяют наращивать производительность системы за счет добавления дополнительных ресурсов.

эти две проблемы являются антагонистическими целями. The классический подход защитить shared datastructure с глобальные блокировки. Это гарантирует 100% правильность, но предотвращает масштабирование производительности и особенно уровня параллелизма выше определенной степени, поскольку общие блокировки приводят к "перегрузке трафика"

кстати, вам нужно быть осторожным при использовании термина "lock free". Строго говоря, совместные операции никогда не могут быть 100% свободными от блокировки. Но возможно организовать сотрудничество умно, чтобы уменьшить влияние блокировки на тех партнеров, которые действительно необходимо получить доступ к тому же элементу одновременно.