【问题标题】:What is the difference between `Synclock syncroot` and `SyncLock Me`?`Synclock syncroot` 和 `SyncLock Me` 有什么区别?
【发布时间】:2010-05-19 07:07:42
【问题描述】:

vb.Net 多线程问题:

有什么区别

SyncLock syncRoot  
  ''# Do Stuff  
End SyncLock

-和-

SyncLock Me  
  ''# Do Stuff  
End SyncLock

【问题讨论】:

    标签: vb.net multithreading synclock


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      如果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 保护的代码使用相同的对象被有效地序列化了。

      【讨论】:

      • 我刚刚注意到“使用”一词在第二段第一句中背靠背出现。它在内容编辑器文本框中不会以这种方式出现。 SO中的错误?
      【解决方案3】:

      您正在锁定不同的对象。

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

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

      【讨论】:

      • 我对 SyncLock 有点困惑。 synclock 会阻止更改我传递给它的变量(在本例中为syncRoot),还是只是锁定代码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      相关资源
      最近更新 更多