std::shared_mutex vs std::mutex
От: xoreaxeax  
Дата: 18.02.15 16:36
Оценка:
Здравствуйте.
Долго гуглил, но до конца не понял, когда реально имеет смысл использовать shared_mutex. При каких количествах тредов, времени выполнения задач. Может быть кто-то может реальный кейс использования рассказать? Спасибо
Re: std::shared_mutex vs std::mutex
От: ArtDenis Россия  
Дата: 18.02.15 16:50
Оценка:
Здравствуйте, xoreaxeax, Вы писали:

X>Долго гуглил, но до конца не понял, когда реально имеет смысл использовать shared_mutex. При каких количествах тредов, времени выполнения задач. Может быть кто-то может реальный кейс использования рассказать? Спасибо


Ну так вроде же достаточно понятно сказано:

Shared mutexes are usually used in situations, when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.

[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: std::shared_mutex vs std::mutex
От: watchmaker  
Дата: 18.02.15 16:52
Оценка:
Здравствуйте, xoreaxeax, Вы писали:


X>но до конца не понял, когда реально имеет смысл использовать shared_mutex.

shared_mutex необходим когда нужен не только эксклюзивный доступ к защищаемому объекту, но и разделяемый. Просто mutex может организовать лишь эксклюзивный доступ.

X>При каких количествах тредов, времени выполнения задач.

Это не относится к выбору std::shared_mutex vs std::mutex. Ну за исключением разных граничных случаев: например, если поток только один, то shared_mutex можно заменить на mutex.
Выбор же делается исходя из набора необходимых операций с данными: если программа выиграет от разделяемого доступа, то нужно задуматься об использовании shared_mutex.

X>Может быть кто-то может реальный кейс использования рассказать?

Задача о читателях-писателях — классика. Возникает везде, где один объект читают и обновляют несколько потоков.
Ну, например, работа с базой данных: много читателей могут одновременно читать из одной и той же таблицы не мешая друг-другу. Но обновление данных в таблице должно быть отделено как от операций чтения, так и от других обновлений.
Отредактировано 18.02.2015 16:56 watchmaker . Предыдущая версия . Еще …
Отредактировано 18.02.2015 16:55 watchmaker . Предыдущая версия .
Re[2]: std::shared_mutex vs std::mutex
От: xoreaxeax  
Дата: 18.02.15 17:00
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, xoreaxeax, Вы писали:



X>>но до конца не понял, когда реально имеет смысл использовать shared_mutex.

W>shared_mutex необходим когда нужен не только эксклюзивный доступ к защищаемому объекту, но и разделяемый. Просто mutex может организовать лишь эксклюзивный доступ.

X>>При каких количествах тредов, времени выполнения задач.

W>Это не относится к выбору std::shared_mutex vs std::mutex. Ну за исключением разных граничных случаев: например, если поток только один, то shared_mutex можно заменить на mutex.
W>Выбор же делается исходя из набора необходимых операций с данными: если программа выиграет от разделяемого доступа, то нужно задуматься об использовании shared_mutex.

X>>Может быть кто-то может реальный кейс использования рассказать?

W>Задача о читателях-писателях — классика. Возникает везде, где один объект читают и обновляют несколько потоков.
W>Ну, например, работа с базой данных: много читателей могут одновременно читать из одной и той же таблицы не мешая друг-другу. Но обновление данных в таблице должно быть отделено как от операций чтения, так и от других обновлений.


Это все и так понятно. Я вот и спрашиваю про то- при каких конкретно случаях(в примерах), перформанс будет лучше. Ибо я так понимаю, что не все так однозначно.
Re[3]: std::shared_mutex vs std::mutex
От: ArtDenis Россия  
Дата: 18.02.15 17:11
Оценка:
Здравствуйте, xoreaxeax, Вы писали:

X>Это все и так понятно. Я вот и спрашиваю про то- при каких конкретно случаях(в примерах), перформанс будет лучше.


Перформанс будет лучше при использованию shared_mutex по назначению Ваш КО
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Отредактировано 18.02.2015 17:11 ArtDenis . Предыдущая версия .
Re[3]: std::shared_mutex vs std::mutex
От: watchmaker  
Дата: 18.02.15 17:25
Оценка:
Здравствуйте, xoreaxeax, Вы писали:



X>Это все и так понятно. Я вот и спрашиваю про то- при каких конкретно случаях(в примерах), перформанс будет лучше.

Пример раз: приведён по ссылке.
Пример два: приведён в сообщении.
Чем не подходят примеры?

X> Ибо я так понимаю, что не все так однозначно.

Ну, в некотором роде, да, не однозначно. Но это неоднозначность на уровне вопроса «что лучше, вилка или чайная ложка?». Можно, конечно, их абстрактно посравнивать, но обычно интуиция всё же верно подсказывает каким из этих инструментов лучше есть конкретное блюдо. А если не подсказывает, то rtfm — опять же по приведённым ссылкам об этом уже написано.
Re: std::shared_mutex vs std::mutex
От: Patalog Россия  
Дата: 18.02.15 17:26
Оценка:
Здравствуйте, xoreaxeax, Вы писали:

[]

X>Может быть кто-то может реальный кейс использования рассказать? Спасибо


Мне оно понадобилось пока ровно один раз (речь про концепцию, а не именно std::shared_mutex).
Примерно в след. случае — в системе летают нек. объекты, которые созданы в нек. аллокаторе и время их жизни отслеживается по счетчику ссылок. Объекты не мои, я имею к ним доступ только через интерфейсы и не могу менять их поведение — т.е. вообще это все свыше данная архитектура, изменить которую я не могу.

Мне понадобилось влезть в эту систему, таким образом, чтобы была возможность аллокатор в системе подменить — этакий hot swap. Понятно, что сделать это можно только при определенных условиях — когда нет ссылок на этот аллокатор, т.е. нет живых объектов, которые созданы на этом аллокаторе.

Так вот, сделано это было след. образом — вместо реального объекта создавался нек. proxy, который имел в себе этот самый shared mutex и при обычных условиях вел себя как обычный объект, т.е. обеспечивал не эксклюзивный (прозрачный) доступ, а в момент когда нужно было переключить аллокатор — запрашивался эксклюзивный лок и поток блокировался до тех пор, пока время жизни всех созданных на старом аллокаторе объектов не кончиться. Тут прикол именно в том, что блокировать объект я не мог, так как как все сценарии его (объекта) использования, в т.ч. сколько потоков его расшаривают я знать и гарантировать не мог, т.е. мой proxy объект _обязан_ был предоставлять разделяемый доступ.
Почетный кавалер ордена Совка.
Re: std::shared_mutex vs std::mutex
От: chaotic-good  
Дата: 19.02.15 08:13
Оценка:
X>Долго гуглил, но до конца не понял, когда реально имеет смысл использовать shared_mutex. При каких количествах тредов, времени выполнения задач. Может быть кто-то может реальный кейс использования рассказать? Спасибо

Там нужно измерять всегда, ты никогда заранее сам не сможешь понять что будет быстрее, rwlokck или обычный мьютекс. Время выполнения разных операций с мьютексом и rwlock-ом зависит от того, что делают другие потоки и состояния кеш линий. Если разные потоки часто взаимодействуют с мьютексом его захват будет медленным, если нет, то это почти что no-op c временем захвата порядка нескольких наносекунд. С shared мьютексом все немного сложнее, так как там есть два типа блокировок и contended (тоесть под несколькими потоками) захват на чтение может быть не бесплатным. Обычно выбор shared_mutex vs mutex диктуется схемой синхронизации и немножко производительностью.

Ну вот например, есть некий ресурс защищенный мьютексом. Доступ к ресурсу происходит по ключу(хэш таблица). Мы можем расшардить мьютекс и завести массив из N мьютексов вместо одного (размер N сильно больше количества ядер, см. birthday paradox). Теперь для чтения мы должны посчитать хеш от ключа, вычислить индекс мьютекса и захватить соответствующий мьютекс, а для записи — захватить все мьютексы по очереди, в общем для всех потоков порядка. В этом случае, чтение будет практически без накладных расходов на захват мьютексов, так как каждый поток будет хватать свой собственный мьютекс, если происходит обращение к разным ключам, и потоки, по сути, не будут взаимодействовать между собой. Запись будет медленной, поэтому это имеет смысл только тогда, когда запись выполняется редко. Например если это какая-нибудь хэш таблица с какой-нибудь конфигурацией, которая очень редко обновляется.

Теперь про rwlock. В этой схеме можно добиться некоторого ускорения записи заменив обычные мьютексы на rw-мьютексы. В этом случае для чтения отдельного ключа придется захватывать только один мьютекс на чтение, для обновления отдельного ключа — нужно будет захватить один мьютекс на запись. Для того, чтобы обновить группу ключей транзакционно или изменить размер таблицы придется захватывать все мьютексы на запись. В каких-то ситуациях это имеет смысл, так как у тебя может быть набор "горячих" кючей (> 1% от общего числа), которые часто обновляются и ты не хочешь, чтобы это тормозило процесс чтения остальных ключей. Тут выбор в пользу shared мьютекса следует из условий задачи и понимания того, как реально работает система (мы собрали статистику и выяснили что у нас есть часто обновляющиеся ключи).

Как-то так.
Re[2]: std::shared_mutex vs std::mutex
От: xoreaxeax  
Дата: 19.02.15 10:16
Оценка:
Здравствуйте, 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>Как-то так.


Спасибо за ответ, это именно то что я и хотел услышать. Просто думал, что может есть какой-то способ — без статистических данных(без профайлера) сделать четкий выбор.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.