Здравствуйте, chaotic-good, Вы писали:
X>>Долго гуглил, но до конца не понял, когда реально имеет смысл использовать shared_mutex. При каких количествах тредов, времени выполнения задач. Может быть кто-то может реальный кейс использования рассказать? Спасибо
CG>Там нужно измерять всегда, ты никогда заранее сам не сможешь понять что будет быстрее, rwlokck или обычный мьютекс. Время выполнения разных операций с мьютексом и rwlock-ом зависит от того, что делают другие потоки и состояния кеш линий. Если разные потоки часто взаимодействуют с мьютексом его захват будет медленным, если нет, то это почти что no-op c временем захвата порядка нескольких наносекунд. С shared мьютексом все немного сложнее, так как там есть два типа блокировок и contended (тоесть под несколькими потоками) захват на чтение может быть не бесплатным. Обычно выбор shared_mutex vs mutex диктуется схемой синхронизации и немножко производительностью.
CG>Ну вот например, есть некий ресурс защищенный мьютексом. Доступ к ресурсу происходит по ключу(хэш таблица). Мы можем расшардить мьютекс и завести массив из N мьютексов вместо одного (размер N сильно больше количества ядер, см. birthday paradox). Теперь для чтения мы должны посчитать хеш от ключа, вычислить индекс мьютекса и захватить соответствующий мьютекс, а для записи — захватить все мьютексы по очереди, в общем для всех потоков порядка. В этом случае, чтение будет практически без накладных расходов на захват мьютексов, так как каждый поток будет хватать свой собственный мьютекс, если происходит обращение к разным ключам, и потоки, по сути, не будут взаимодействовать между собой. Запись будет медленной, поэтому это имеет смысл только тогда, когда запись выполняется редко. Например если это какая-нибудь хэш таблица с какой-нибудь конфигурацией, которая очень редко обновляется.
CG>Теперь про rwlock. В этой схеме можно добиться некоторого ускорения записи заменив обычные мьютексы на rw-мьютексы. В этом случае для чтения отдельного ключа придется захватывать только один мьютекс на чтение, для обновления отдельного ключа — нужно будет захватить один мьютекс на запись. Для того, чтобы обновить группу ключей транзакционно или изменить размер таблицы придется захватывать все мьютексы на запись. В каких-то ситуациях это имеет смысл, так как у тебя может быть набор "горячих" кючей (> 1% от общего числа), которые часто обновляются и ты не хочешь, чтобы это тормозило процесс чтения остальных ключей. Тут выбор в пользу shared мьютекса следует из условий задачи и понимания того, как реально работает система (мы собрали статистику и выяснили что у нас есть часто обновляющиеся ключи).
CG>Как-то так.
Спасибо за ответ, это именно то что я и хотел услышать. Просто думал, что может есть какой-то способ — без статистических данных(без профайлера) сделать четкий выбор.