`Synclock syncroot`和`SyncLock Me`有什么区别?

时间:2010-05-18 15:10:19

标签: vb.net multithreading synclock

vb.Net多线程问题:

之间有什么区别
SyncLock syncRoot  
  ''# Do Stuff  
End SyncLock

- 和 -

SyncLock Me  
  ''# Do Stuff  
End SyncLock

3 个答案:

答案 0 :(得分:5)

SyncLock块中发生的所有代码都与同一对象上SyncLock内发生的所有其他代码同步。显然,MesyncRoot不同(我假设,Me.SyncRoot,如果您的MeICollection)。

在一个对象的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

以上情况很好:AddRemove调用是同步的,这意味着它们不会同时发生(无论哪个先调用都会执行,第二个调用直到第一个完成才会执行)

但是假设你有这个:

' 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

上述AddRemove来电以任何方式,形状或形式同步。因此,上述代码中没有线程安全性。

现在,为什么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属性背后的想法:它为您提供了一个对象,其目的是提供一个公共对象,通过该对象可以同步对集合的修改/枚举。 以某种其他方式涉及集合的代码 - 但不需要与修改或读取集合内容的代码同步 - 应该同步,在适当的情况下,在不同的对象上。

答案 1 :(得分:3)

如果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 :(得分:2)

你锁定了不同的对象。

如果您的代码(或内部代码)的其他部分在SyncRoot同步,那么您应该通过同步Me来破坏(即引入线程错误)。

你绝对应该在SyncRoot上同步 - 这就是它存在的原因。