На хабре какой-то крендель начал цикл статей о lock-free структурах данных, за обедом как-то подняли эту тему.
Вообще, сихронизация многопоточных программ - достаточно обширная и сложная тема. Даже опытные разработчики сталкиваясь со сложным софтом нередко натыкаются на дедлоки. Я не говорю про примитивы типа клиент-серверного веб-софта, где синхронизация заключается в простом разделении доступа к ресурсам. Я говорю про софт, который одновременно работает с десятком-другим достаточно разнородных объектов-тредов, параллельно работая с написанными левой ногой драйверами к какому-нибудь телевизионному железу (где внезапно приходят колбеки, когда объект уже давно удален, например). Ситуация усложняется если в проект приходят новые люди. Так как С++ поощряет выстрелы себе в ногу, дедлоки становятся реальной проблемой.
Я как-то потратил некоторое время пытаясь сформулировать правила, по которым можно писать "бездедлочные" приложения на плюсах. Свелось к тривиальному (потом про это). Думал про статический анализатор, который бы проверял код на потенциальные дедлоки, но сложность (в том виде в котором к ней заставляют подходить синхронизационные примитивы предоставляемые тем же posix) проблемы оказалась велика. В Microsoft DDK есть забавный софт, использующий движок
SLAM, по которому написана куча whitepapers, где умные люди пытаются строить математическую модель безглючного софта (точнее, позволяющую детектить глюки в софте с всего порядка 10% ложных срабатываний). Но SLAM используется только для анализа кода драйверов на достаточно небольшом объеме кода.
Короче говоря, я на текущий момент не придумал ничего умнее примерно следующего
1) (очевидное) не делать мьютексов там, где можно обойтись незамороченным lock-free
2) объекты на стадии многопоточной работы (инициализация вполне может быть, и в идеале должна быть однопоточной) обращаются друг к другу только в одном, заранее известном направлении (получается граф, который нигде не замкнут)
3) любые обратные связи (ошибка в рабочем треде объекта, например) должны строиться через очередь сообщений, обрабатываемую асинхронно в основном рабочем потоке принимающего объекта
Потому что достаточно проблематично сделать дедлок в типичном кейсе, где один пишет, другой - читает. Таким образом, исключается возможность стандартной ошибки, когда, например, объект-менеджер дает команду объекту-исполнителю, в то время как объект-исполнитель репортит ошибку объекту-менеджеру (я неоднократно за годы натыкался на различные производные этого кейса).
Есть другой достаточно забавный подход, который в принципе похож, я его наблюдаю достаточно давно в соседнем отделе. Там просто не пишут многопоточный софт, эти ребята пишут на Objective-C и специально выпилили многопоточку, заменив главный loop программы на libev. Если им что-то нужно делать одновременно - они запускают другой или еще один процесс и общаются с ним через ZMQ. Тоже, в принципе, решение. Не без минусов, но принцип тот же. И гораздо более утойчиво к текучке на проекте, by design заставляет людей писать без дедлоков. Но на С++ писать таким образом я бы не хотел.
Параллельно меня забавляет ситуация с опытом по созданию многопоточных приложений среди С++ программистов, я неоднократно объяснял и видимо буду это на собеседованиях спрашивать. Но практически никто без подсказки не пользуется средствами языка для минимизации количества мьютексов.
Взять тот же пример объектом-менеджером и объектом-исполнителем. Объекту-менеджеру нужно знать статус объекта исполнителя, какую-нибудь статистику, которую удобно выводить в статус приложения. Статистика стоит из POD'ов каких-нибудь. Чтоб усложнить задачу - пусть там будет парочка string'ов. Что делает разработчик? Разработчик делает мьютекс, который лочится в момент изменения переменных статуса (в рабочем потоке) и в момент чтения из них (по запросу менеджера). Собственно вопрос - как избавиться от этого мьютекса (не жертвуя consistency данных и не заменяя все на POD'ы) используя средства STL или BOOST? (кстати, что характерно, человек на хабре, вещающий про lock-free для C++, говорит что не имел еще опыта с boost).