Search code examples
vb.netmultithreadingsynclock

What is the difference between `Synclock syncroot` and `SyncLock Me`?


vb.Net multithreading question:

What is the difference between

SyncLock syncRoot  
  ''# Do Stuff  
End SyncLock

-and-

SyncLock Me  
  ''# Do Stuff  
End SyncLock

Solution

  • 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.