Dex & Unsociable
Я тут как раз очередь многопоточную отлаживал, запутался в какой-то тонкой гонке. У тебя в последнее время чего-нибудь похожего не попадалось?
Привет, знаешь, race conditions – это как призраки в коде. Записывай каждое добавление и удаление из очереди с ID потока и временными метками, потом смотри, нет ли событий в неправильном порядке. Если это не поможет, переходи на атомарную очередь или добавь нормальный мьютекс вокруг критической секции. Обычно это превращает загадку в то, что можно логически объяснить.
Звучит неплохо – я начну ставить временные метки для каждой операции и понаблюдаю за странными выбросами. Если блокировка всё равно покажется слишком грубой, попробуй библиотеку неблокирующей очереди. Какие посоветуешь, самая проверенная?
Можешь попробовать очереди из ConcurrencyKit или Intel TBB — они проверены боем и используются в продакшене. Если нужно что-то попроще, то `std::queue` с обёрткой `boost::lockfree::queue` тоже неплохо работает. Выбирай, что больше подходит под твой язык и требования к производительности.
Спасибо за предложения. Я добавил TBB и ConcurrencyKit в тестовую среду и начал профилирование. TBB показался немного избыточным для моих задач, а вот ConcurrencyKit удивил своей легкостью. Скорее всего, сначала я оберну std::queue с использованием boost::lockfree::queue для микро-тестов. У тебя есть опыт работы с безблокирующей реализацией для высокочастотных потоков данных?
Привет,
Я только пару раз набросал lock-free очереди для проектов, но видел, как они справляются с десятками миллионов операций в секунду, когда конкуренция небольшая. Главное – держать размер очереди маленьким и избегать постоянной перевыделения памяти: если можешь, выделяй узлы заранее. И еще, используй ограниченную очередь, если производитель не успевает – тогда она превращается в кольцевой буфер и отпадает необходимость в выделении памяти из кучи. Если возникнет зависание, чаще всего виновата проблема ABA – используй помеченные указатели или схему hazard pointer, чтобы обезопасить себя. Если поток данных действительно очень интенсивный, lockless кольцевой буфер обычно самый простой и быстрый вариант.
Понял—предварительное выделение узлов и использование кольцевого буфера с ограничением размера, похоже, подходит для моей задачи. Добавлю простую проверку указателей с метками, чтобы обезопасить от ABA. Спасибо за подсказку!
Рад, что всё сошлось. Просто следи за локальностью кэша; даже плотное кольцевой буфер может тормозить, если узлы оказываются в разных строках кэша. Удачи.
Спасибо, учту кэш-линии при определении размера буфера. Если что-то выскочит – дам знать.