Как стать автором
Обновить

Комментарии 26

ЗакрепленныеЗакреплённые комментарии

Mutex как правильно указали - работает на уровне ОС. Поэтому сгодится например для обеспечения запуска 1 копии приложения (можно использовать global для ограничения между пользователями\сессиями).

Пример AutoResetEvent явно показывает, что сейчас лучше работать с тасками - возвращать Task из вашего метода и await-ить его.

В нынешнем дотнете есть ещё Lazy, который часть задач на себя берёт, которые раньше решались как раз чем-то типа lock.

И картинки вместо кода, ну как так-то? Не все, кто читает вашу статью, способны воспринимать визуальную информацию. А могло бы быть весьма полезно.

Благодарю. В следующий раз постараюсь разобраться с редактором кода лучше. В этот раз текст из него выглядел крайне некрасиво, но подозреваю, что я что-то делал не так.

Mutex как правильно указали - работает на уровне ОС. Поэтому сгодится например для обеспечения запуска 1 копии приложения (можно использовать global для ограничения между пользователями\сессиями).

Пример AutoResetEvent явно показывает, что сейчас лучше работать с тасками - возвращать Task из вашего метода и await-ить его.

В нынешнем дотнете есть ещё Lazy, который часть задач на себя берёт, которые раньше решались как раз чем-то типа lock.

Про Lazy слышал, но кроме как в учебных примерах не пользовался, поэтому забыл. Благодарю за напоминание.

Аналог AutoResetEvent в тасках - TaskCompletionSource

AutoResetEvent используется для других совсем сценариев. Простой пример - бесконечный цикл процессинга какой-нибудь очереди. Пока очередь пуста - ивент ожидает, потоки не занимает. В методе, который ставит сообщения (или прямо готовые экземпляры обработчиков) после постановки в очередь выполняется сет, ивент срабатывает, процессинг запускается. Очередь опустела - все опять на паузе.

Согласен, такой вариант таской не заменить, таска для одноразового ожидания =)

Насколько понимаю все эти ResetEvent уже вообще не нужны давно. Для тех же очередей уже есть готовые классы

Для описанного сценария (конвейер) никаких готовых классов нету. Готовый класс очереди это обычная FIFO коллекция. Реализация конвейера через ResetEvent до сих пор наиболее оптимальна и востребована достаточно часто.

Есть и другие сценарии. ResetEvent классы используются не менее широко чем все остальные наследники иерархии WaitHandle, такие как мьютексы и семафоры. Причем и самим майкрософтом они используются, в самых свежих реализациях.

Разумеется больше они используются в десктопе и мобайле, на бэкэнде в принципе редко приходится возиться с синхронизацией потоков, а те же конвейеры реализуются на каких-нибудь месседж брокерах.

Чем это отличается от чего-то типа DataFlow?

Накладными расходами, очевидно.

Сам семафор предоставляется ОС и используется для того, чтобы ограничить число одновременных пользователей ресурса.

Какой вывод можно из этого заключить? Что SemaphoreSlim можно использовать для межпроцессорной синхронизации?

Тут да, ошибся и не раскрыл разницу между Semaphore и SemaphoreSlim, прошу прощение. SemaphoreSlim не подойдет для межпроцессорной синхронизации, для этой задачи нужно использовать именно Semaphore.

Такой, на который фантазия позволяет - ограниченный доступ к ресурсу, например тротлинг, degree of parallelism - самые распространенные случаи использования. Если бы я писал про Interlocked - то упомянул бы про общие черты с volatile, и про ключевые отличия в этом их общем разрезе, так сказать. Речь о запрете на reordering optimization.

Не упомянуты ReaderWriterLockSlim/ReaderWriterLock, CountdownEvent, volatile/ MemoryBarrier, не раскрыта разница между AutoResetEvent и ManualResetEvent. Про lock тоже можно было бы рассказать поподробнее (что это синтаксический сахар над Monitor.Enter/ Monitor.Exit)

Не приходилось сталкиваться на практике с этими классами, поэтому не написал, спасибо, изучу и их. По поводу lock не хотел углубляться в реализацию.

На скриншоте не убунта, так что вопрос сомнительный.

С глобалом (а в вопросе он) на линуксах точно работало.

Semaphore использует Monitor.WaitHandle.

Lock использует Monitor.WaitHandle.

AutoResetEvent использует Monitor.WaitHandle.

И всё это использует объекты ядра операционки - mutex.

SemaphoreSlim тоже использует мьютексы, когда не может обойтись атомарками (interlocked). Вообще, худые семафоры - это попытка сэкономить на использовании мьютексов за счёт атомарных операций. Очень удачная, надо сказать.

Статья - безграмотная чушь.

Ну неправда же. Lock использует Monitor.Enter. И дальше я не копал, но очень сомнительно, что дальше это работает на мьютексе - объекте межпроцессной синхронизации.

Монитор устроен довольно сложно, но если опускать детали, то он сначала крутится в спинлоке на уровне юзерленда с проверкой того самого поля синхронизации в хэдере объекта, а потом, если прошло много времени, создает объект синхронизации уровня ядра типа Event и паркует тред. Это все описано у рихтера под названием "hybrid lock".

Это да, но я знал что так сделано на Windows, там, кажется, так работает EnterCriticalSection. Как сейчас на NET Core и на других платформах - не знаю, буду благодарен, если кто просветит.

https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/syncblk.cpp

Это те вещи, которые я часто встречаю во время работы

А что сфера разработки? В бэке за 7 лет только локи иногда встречал и 1 раз AutoResetEvent, и то там тасками можно было обойтись.

Это все слишком сложно, я использую вместо этого паттерн Consumer-Producer паттер для определения количества исполнителей.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории