Поменяли object на Lock, и два потока встретились в критической секции
#dotnet #csharp #concurrency
✅
С C# 13 тип выражения в lock решает семантику, а не только скорость: object разворачивается в Monitor, System.Threading.Lock — в EnterScope, и это два несовместимых замка на одном объекте.
📈
Один объект Lock, прочитанный через object или через generic-параметр, тихо возвращает вас к Monitor — и взаимное исключение исчезает без единой ошибки компиляции.
🔧 Утечка происходит не в самом lock, а в строке, где экземпляр кладут в поле типа object или в Dictionary: два потока по 150 000 проходов встретились в критической секции 106 309 раз, счётчик потерял 4487 инкрементов.
⚠️ Обёртка `lock (gate)` в универсальном методе `LockAny` компилируется в Monitor молча — предупреждения нет, а `where T : Lock` невозможен, потому что Lock объявлен sealed.
Читаем:
В статье разбор того, где именно компилятор молчит, почему Monitor.IsEntered начинает врать, что происходит с Monitor.Wait/Pulse, замеры памяти (Lock +16 байт на экземпляр против раздувания Monitor) и порядок безопасной миграции через CS9216 как ошибку сборки.
https://habr.com/ru/companies/otus/articles/1087292/
@aStateOfNet
#dotnet #csharp #concurrency
✅
С C# 13 тип выражения в lock решает семантику, а не только скорость: object разворачивается в Monitor, System.Threading.Lock — в EnterScope, и это два несовместимых замка на одном объекте.
📈
Один объект Lock, прочитанный через object или через generic-параметр, тихо возвращает вас к Monitor — и взаимное исключение исчезает без единой ошибки компиляции.
🔧 Утечка происходит не в самом lock, а в строке, где экземпляр кладут в поле типа object или в Dictionary: два потока по 150 000 проходов встретились в критической секции 106 309 раз, счётчик потерял 4487 инкрементов.
⚠️ Обёртка `lock (gate)` в универсальном методе `LockAny` компилируется в Monitor молча — предупреждения нет, а `where T : Lock` невозможен, потому что Lock объявлен sealed.
Читаем:
В статье разбор того, где именно компилятор молчит, почему Monitor.IsEntered начинает врать, что происходит с Monitor.Wait/Pulse, замеры памяти (Lock +16 байт на экземпляр против раздувания Monitor) и порядок безопасной миграции через CS9216 как ошибку сборки.
https://habr.com/ru/companies/otus/articles/1087292/
@aStateOfNet