Search code examples
vb.netmultithreadingsynclock

Is it safe to call SyncLock and MemoryBarrier even if you're not in a separate thread?


A follow-up to this post. My goal is to have only one Calculate at a time, so I have added a SyncLock:

Public Sub Calculate(Optional inBack As Boolean = True)
    If Not inBack Then
        InternalCalculate(-1, False)
    Else
        If CalcThread IsNot Nothing Then
            CalcThread.Abort() ' yes, I will replace this
            CalcThread = Nothing ' XXX
        End If
        If CalcThread Is Nothing Then
            CalcThread = New Threading.Thread(AddressOf InternalCalculate)
            CalcThread.IsBackground = True
        End If
        CalcThread.Start()
    End If
End Sub

Private Sub InternalCalculate(Optional Line As Integer = -1, Optional isBack As Boolean = True)
    Dim Lock As New Object
    SyncLock Lock
         Threading.Thread.MemoryBarrier() ' do this BEFORE a write, right?
         isRunning = true
        'do the expensive stuff
    End SyncLock
End Sub

Note the isBack. If this is false the code should just run in main. This is commonly used when recalculating a single Line. So my question is about the safety of these two lines:

SyncLock Lock
Threading.Thread.MemoryBarrier()

It is not clear to me in the documentation what happens if I call these in code running in main. I have added the code, and it seems to run OK, but I want to make sure I'm not opening myself to another gotcha, like Abort. Are these OK for both threaded and non-threaded uses?


Solution

  • Yes it's safe to use them in single threaded code.

    There are issues however with your InternalCalculate which will allow it to execute code concurrently. Every call to InternalCalculate creates a new Lock object. Synclock will only block threads if these use the same object so make Lock a readonly member variable.

    If you then execute multiple threads then the second, third, fourth etc will wait until the first one to obtain the lock exits the sync lock block. Then the others will go. So if this is code that should only be executed once you should check out the double check lock pattern.

    Instead of adding MemoryBarriers for the reading / writing of volatile data, I'd suggest you use System.Threading.Thread.VolatileRead and System.Threading.Thread.VolatileWrite. Then you don't need to remember which order to do your reads / writes in.