Комментарии 9
Спасибо за статью.
Не могу оценить вашу реализацию, но хотелось бы еще послушать, как ваш подход к реализации отличается/схож с походом folly/libcds.
В общем, в чем отличие вашей реализации от того, как оно в серьезных библиотеках реализовано.
Добрый день, я ознакомился с реализацией folly и немного с libcds. Концептуально идея HP у нас схожая, protect, retire, архитектура также схожая. Но вот как это реализовано и какие доп фичи есть - тут пропасть.
Например у folly есть когорты, чтобы гарантировать синхронное удаление объектов, как я понимаю. Так как в стандартных HP никогда не знаешь когда удалится указатель.
Или используется например, как я понял, F14set вместо vector<void*> active_hp как у меня.
Код этих либ - результат длительного профилирования и оптимизации узких мест.
На практике главная боль — выбрать число hazard pointers. Один раз retire() копил объекты, пока читатели висели — утечка 200МБ под нагрузкой. Совет: сразу делайте мониторинг retired-очереди.
LFA::unique_lock_guard lock(state.registration_mutex);
Это, конечно, мелочь. Но именно она делает весь код не lock-free. Я пытался найти полностью lock-free варианты решения этой проблемы, но, похоже, их не существует. Точнее, это можно сделать, но появляются другие неприятные ограничения, например, жесткий лимит на количество потоков.
Насколько я понимаю, для лок-фри списка понадобятся все те же хазард-пойнтеры. Круг замкнется.
если вы собираетесь удалять зарегистрированные потоки, то подойдут и tagged pointers
С ними тоже что-то было не так, уже не помню, что именно. Я искал универсальное решение, которое могло бы работать и с пулом долгоживущих потоков, и с большим количеством короткоживущих потоков, создаваемых на одну операцию. Все найденные варианты либо не были полностью лок-фри, либо имели какие-то ограничения вроде лимита на количество потоков.
Хазартпоитер ещё решает проблему инвалидации кэшей процессора.

Hazard pointers на пальцах