vb. Сетевой вопрос о многопоточности:
Между чем различие
SyncLock syncRoot
''# Do Stuff
End SyncLock
- и -
SyncLock Me
''# Do Stuff
End SyncLock
Весь код, который происходит в блоке SyncLock
, синхронизируется со всем остальным кодом, происходящим в блоке SyncLock
того же объекта . Очевидно, Me
- это не то же самое, что syncRoot
(то есть, я предполагаю, Me.SyncRoot
, если ваш Me
ICollection
).
Код, происходящий в блоке SyncLock
одного объекта, не будет синхронизироваться с кодом в блоке SyncLock
другого объекта.
Допустим, у вас есть этот код:
' happening on thread 1 '
SyncLock myColl.SyncRoot
myColl.Add(myObject)
End SyncLock
' happening on thread 2 '
SyncLock myColl.SyncRoot
myColl.Remove(myObject)
End SyncLock
Вышеупомянутое нормально: вызовы Add
и Remove
синхронизированы, то есть они не будут выполняться одновременно (в зависимости от того, что вызывается первым, будет выполнено , а второй не будет выполняться, пока не будет завершен первый).
Но предположим, что вместо этого у вас было следующее:
' happening on thread 1 '
SyncLock myColl.SyncRoot
myColl.Add(myObject)
End SyncLock
' happening on thread 2 '
SyncLock myColl ' NOTE: SyncLock on a different object '
myColl.Remove(myObject)
End SyncLock
Вышеупомянутые вызовы Add
и Remove
не синхронизированы каким-либо образом, формой или формой. Таким образом, в приведенном выше коде нет потоковой безопасности.
Итак, почему существует SyncRoot
? Все очень просто, потому что имеет смысл синхронизировать в наименьшем необходимом масштабе; т.е. нет необходимости синхронизировать код, который на самом деле не нуждается в синхронизации.
Рассмотрим следующий пример:
' happening on thread 1 '
SyncLock myColl
myColl.Add(myObject)
End SyncLock
' happening on thread 2 '
SyncLock myColl
' Why you would have code like this, I do not know; '
' this is just for illustration. '
myColl.Name = myColl.Name.Replace("Joe", "Bill")
End SyncLock
' happening on thread 3 '
SyncLock myColl
myColl.Name = myColl.Name.Replace("Bill", "Joe")
End SyncLock
В приведенном выше примере вы синхронизируете больше, чем необходимо . Вызов Add
действительно не имеет ничего общего с переименованием объекта myColl
; таким образом, код не нужно синхронизировать.
В этом заключается идея свойства SyncRoot
: оно дает вам объект, вся цель которого - предоставить общий объект, с которым могут быть синхронизированы модификации / перечисления коллекции. Код, который включает коллекцию каким-то другим способом - но который не требует синхронизации с кодом, который изменяет или считывает содержимое коллекции - должен быть синхронизирован, где это необходимо. , на другом объекте.
Вы блокируете разные объекты.
Если другие части вашего кода (или внутренний код) синхронизируются на SyncRoot
, что и должно быть, то вы ломаете вещи (т.е. вносите ошибки в потоки), синхронизируясь на Me
.
Вы определенно должны синхронизироваться на SyncRoot
- вот почему он там.
Если Object.ReferenceEquals(syncRoot, Me) = True
, то ничего не изменилось. В противном случае блокировка приобретается с использованием разных объектов.
Если ваше использование syncRoot
эквивалентно ICollection.SyncRoot
, то блокировка будет получена с помощью того же объекта, который используется внутри коллекции для собственной блокировки. Это позволяет синхронизировать доступ к перечислителям. Например:
SyncLock collection.SyncRoot
For Each item As Object in collection
Next
End SyncLock
По традиции разработчики .NET избегают использовать Me
в качестве объекта блокировки. Это особенно верно, если Me
ссылается на объект, который виден в публичном API библиотеки классов. Мы избегаем этого потому, что другой код может использовать тот же объект для получения блокировки по причине, которая конфликтует с семантическим поведением, которое вы пытаетесь реализовать в своем коде. Этот конфликт может привести к узким местам или даже к тупиковым ситуациям.
Следует отметить, что SyncLock
не синхронизирует доступ к самому объекту блокировки, а скорее к коду, обернутому конструкцией SyncLock
. Другими словами, код, который охраняется SyncLock
, использующим тот же объект, эффективно сериализуется.