views:

180

answers:

3

vb.Net multithreading question:

What is the difference between

SyncLock syncRoot  
  ''# Do Stuff  
End SyncLock

-and-

SyncLock Me  
  ''# Do Stuff  
End SyncLock
+2  A: 

You're locking on different objects.

If other parts of your code (or internal code) sync on SyncRoot, which they should, then you're breaking things (i.e. introducing threading bugs) by syncing on Me.

You should definitely sync on SyncRoot--that's why it's there.

Michael Haren
I'm a little bit confused about SyncLock. Does synclock prevent changes to the variable that I pass to it (in this case, `syncRoot`), or does it simply lock the <em>code</em>?
Rice Flour Cookies
+2  A: 

All code that happens within a SyncLock block is synchronized with all other code happening within a SyncLock block on the same object. Obviously, Me is not the same as syncRoot (which is, I'm assuming, Me.SyncRoot, if your Me is an ICollection).

Code happening within a SyncLock block on one object is not going to be synchronized with code within a SyncLock block on a different object.

Say you have this code:

' happening on thread 1 '
SyncLock myColl.SyncRoot
    myColl.Add(myObject)
End SyncLock

' happening on thread 2 '
SyncLock myColl.SyncRoot
    myColl.Remove(myObject)
End SyncLock

The above is fine: the Add and Remove calls are synchronized, meaning they will not occur simultaneously (whichever gets called first will execute, and the second will not execute until the first is finished).

But suppose you had this instead:

' 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

The above Add and Remove calls are not synchronized in any way, shape, or form. Thus there is no thread safety in the above code.

Now, why does SyncRoot exist? Quite simply, because it makes sense to synchronize on the smallest scale necessary; i.e., there is no need to synchronize code that doesn't actually need to be synchronized.

Consider this example:

' 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

In the above, you are synchronizing more than necessary. The Add call really has nothing to do with the renaming of the myColl object; thus the code does not need to be synchronized.

This is the idea behind the SyncRoot property: it gives you an object whose entire purpose is to provide a common object with which modifications to/enumerations of the collection can be synchronized. Code that involves the collection in some other way -- but which does not need to be synchronized with code that modifies or reads the contents of the collection -- should be synchronized, where appropriate, on a different object.

Dan Tao
+2  A: 

If Object.ReferenceEquals(syncRoot, Me) = True then nothing is different. Otherwise the lock is acquired using different objects.

If your use of syncRoot is equivalent to ICollection.SyncRoot then the lock will be acquired using the same object that is used internally by the collection for its own locking. This allows you to synchronize access to enumerators. For example:

SyncLock collection.SyncRoot
  For Each item As Object in collection
  Next
End SyncLock

As a matter of convention .NET developers avoid using Me as the lock object. This is especially true if Me references as object that is visible to the public API of a class library. The reason we avoid this is because other code may use the same object to acquire a lock for a reason that conflicts with the semantic behavior you are trying to accomplish in your code. This conflict can lead to bottlenecks or even deadlocks.

It should be noted that SyncLock does not synchronize access to the lock object itself, but rather the code wrapped by the SyncLock construct. In other words, code that is guarded by a SyncLock using the same object is effectively serialized.

Brian Gideon
I just noticed that the word "using" appears back-to-back in the 2nd paragraph 1st sentence. It does not appear that way in the content editor textbox. Bug in SO?
Brian Gideon