С развитием многопоточного программирования появилась проблема одновременного доступа нескольких потоков к одним и тем же данным. Это приводило к непредсказуемым багам и повреждениям состояния программы.
В Visual Basic .NET применяют механизм эксклюзивной блокировки с помощью конструкции SyncLock, чтобы гарантировать, что только один поток одновременно выполняет определенный код.
Решение — использовать SyncLock (или Monitor.Enter/Exit) вокруг кода доступа к разделяемым ресурсам, чтобы блокировать объект на время выполнения критической секции.
Пример кода:
Private Shared Counter As Integer = 0 Private Shared ReadOnly CounterLock As New Object() Public Shared Sub IncrementCounter() SyncLock CounterLock Counter += 1 End SyncLock End Sub
Ключевые особенности:
Можно ли использовать в качестве токена блокировки значение типа Integer, String или Nothing?
Нет, SyncLock требует ссылочного (Reference) объекта. Строки не рекомендуются, для них возможен interning, что приведёт к неявному пересечению блокировок.
Что будет, если разные потоки используют разные объекты для блокировки одной переменной?
Не будет никакой синхронизации, и возникает гонка потоков — блокировать нужно строго один и тот же объект.
Нужно ли вручную освобождать блокировку после выхода из блока SyncLock?
Нет, разблокировка происходит автоматически при выходе из блока, даже при исключениях.
В коде используются строки для SyncLock, несколько частей программы используют одинаковые строковые литералы. В результате разные блокировки пересекаются и появляются неожиданные взаимные блокировки (deadlocks).
Плюсы:
Минусы:
Для каждой критической секции объявляется отдельный ReadOnly-объект. Блокируется только минимальный, реально нужный участок кода.
Плюсы:
Минусы: