Search code examples
vb.netsynclock

SyncLock the same object from two different threads


Basically I have a global variable, such as...

Dim int1 as integer

And then I have two asynchronous functions, such as...

function bleh()
    int1 += 1
end function

and

function Meh()
     int1 -= 1
end function

Both these functions are being run by Task.Run().

I want to use SyncLock in both these functions. However, all the examples given on the MSDN site only show examples of SyncLock being used within a single function. So I can't tell simply from the MSDN description if it is "okay" for me to use SyncLock across two different functions, on a global variable.

What I want to do is something like this:

Private Shared SyncObj as Object '<-- global
Dim int1 as integer '<-- global

Sub Form_Load(...)
     SyncObj = new Object
     Task.Run(Function() bleh())
     Task.Run(Function() Meh())
End Sub

Function bleh()
     SyncLock SyncObj
        int1 += 1
     End SyncLock
End Function
Function Meh()
     SyncLock SyncObj
        int1 -= 1
     End SyncLock
End Function

Is this okay to do? Will bleh() block Meh() from changing int1, and vise versa? Thanks! Sorry for the VB lol.


Solution

  • Yeah It is OK. SyncLock is designed for that. It avoids other thread accessing to a resource while other thread is working with it. I recommend you to do a Console.Writeline or Debug.Writeline to follow its output.

    Add a While true to check how the values are changing:

    Sub Form_Load(...)
         SyncObj = new Object
         While true
          Task.Run(Function() bleh())
          Task.Run(Function() Meh())
         End while     
    End Sub
    
    Function bleh()
         SyncLock SyncObj
            int1 += 1
            Debug.Writeline("from thread bleh: " & int1.toString)
         End SyncLock
    End Function
    Function Meh()
         SyncLock SyncObj
            int1 -= 1
             Debug.Writeline("from thread meh: " & int1.toString)
         End SyncLock
    End Function
    

    The Synclock, will prevent bleh() to access that code while meh() is working with it, and viceversa.

    EDIT: I executed your code and this is the output:

    from thread meh: -1

    from thread meh: -2

    from thread bleh: -1

    from thread bleh: 0

    from thread bleh: 1

    from thread meh: 0

    from thread bleh: 1

    from thread meh: 0

    from thread bleh: 1

    from thread meh: 0

    from thread meh: -1

    from thread bleh: 0

    from thread bleh: 1

    from thread meh: 0

    from thread bleh: 1

    from thread bleh: 2

    from thread meh: 1

    from thread meh: 0

    from thread meh: -1

    from thread bleh: 0

    You block the access to int1, but you can't control one thread to execute two times before the other one is triggered as you can see.

    This could be useful using another Example, for example with a File, It can't be accesed from two threads at a time or it will give a exception.

    Here you have the example:

     Imports System.Threading.Tasks
    Imports System.IO
    
    Module Module2
    
        Dim SyncObj As Object
    
        Dim path As String = "c:\testfile.text"
        Sub Main()
    
            SyncObj = New Object
            While True
                Task.Factory.StartNew(Function() bleh())
                Task.Factory.StartNew(Function() Meh())
            End While
        End Sub
    
        Function bleh()
            SyncLock SyncObj
    
                Using sw As New StreamWriter(path, True)
                    sw.WriteLine("From bleh!!!")
                End Using
            End SyncLock
        End Function
        Function Meh()
            SyncLock SyncObj
                Using sw As New StreamWriter(path, True)
                    sw.WriteLine("From meh!!!")
                End Using
            End SyncLock
        End Function
    
    End Module
    

    This example wrote 26814 lines on the path file without any exception in some seconds, so concurrent access to the resource did not happen.