В чем разница между Synclock syncroot и SyncLock Me? - PullRequest
5 голосов
/ 18 мая 2010

вопрос многопоточности vb.Net:

В чем разница между

SyncLock syncRoot  
  ''# Do Stuff  
End SyncLock

-и-

SyncLock Me  
  ''# Do Stuff  
End SyncLock

Ответы [ 3 ]

5 голосов
/ 18 мая 2010

Весь код, который происходит в блоке 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: оно дает вам объект, цель которого состоит в том, чтобы предоставить общий объект, с которым можно синхронизировать изменения / перечисления коллекции. Код, который включает коллекцию некоторым другим способом - но который не нужно синхронизировать с кодом, который изменяет или читает содержимое коллекции - должен быть синхронизирован, где это необходимо , на другом объекте.

3 голосов
/ 18 мая 2010

Если 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 с использованием того же объекта, эффективно сериализуется.

2 голосов
/ 18 мая 2010

Вы блокируете разные объекты.

Если другие части вашего кода (или внутреннего кода) синхронизируются на SyncRoot, что они должны делать, то вы ломаете вещи (то есть вносите ошибки в потоки), синхронизируя на Me.

Вы обязательно должны синхронизироваться на SyncRoot - вот почему он там.

...