Question Is this code thread-safe?

aaaron

Well-known member
Joined
Jan 23, 2011
Messages
219
Programming Experience
10+
VB.NET:
  Private Sub Button6_CreateNonUiThread_Click(sender As Object, e As EventArgs) Handles Button6_CreateNonUiThread.Click
      Using ofd As New OpenFileDialog
          ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
          ofd.Filter = ImageFileFilterPairsForOpen()
          ofd.FilterIndex = 1   
          ofd.Multiselect = False
          If ofd.ShowDialog() = DialogResult.OK Then
              Me.TextBox6_DisplayPath.Text = ofd.FileName
          End If
      End Using
      Me.PictureBox6_1.BackgroundImageLayout = ImageLayout.Stretch
      Dim updateThread As New System.Threading.Thread(Sub() Me.NonUIThreadSub6(Me.TextBox6_DisplayPath.Text))
      updateThread.Start()
  End Sub
  Public Delegate Sub ThreadSafeCallBackDelegateType6(text As String)
  Public Sub NonUIThreadSub6(imgPath As String)
      Me.PictureBox6_1.Invoke(New ThreadSafeCallBackDelegateType6(AddressOf Me.SetBackgroundImageFromPath6), New Object() {imgPath})
  End Sub
  Private Sub SetBackgroundImageFromPath6(txt As String)
      Me.PictureBox6_1.BackgroundImage = Image.FromFile(txt)
  End Sub

Is the above thread-safe (and otherwise O.K.)?
 
Last edited:
I think that you should be assigning Me.TextBox6_DisplayPath.Text to a local variable and using that in your lambda rather than using the control property directly.
 
I think that you should be assigning Me.TextBox6_DisplayPath.Text to a local variable and using that in your lambda rather than using the control property directly.

What's your reasoning? I just like to know.


Also, don't I need: If InvokeRequired?

I've always used it on created threads.
 
Last edited:
I didn't really think about it before but now I think that this is sounding rather like an interview/test question that you're trying to get us to do for you. How about you explain what you think and then we can confirm it if you're correct or help you look elsewhere if you're wrong?
 
Thanks. I found out what was bothering me.
I had also used nvokeRequire because I thought I had to with threads.
  • In some cases, you might not always need to use Invoke if the code is already running on the UI thread. InvokeRequired helps you determine this.
  • Example: Imagine you have a button click event handler that can be triggered from either the UI thread (user interaction) or a background thread (e.g., a timer event). The update logic might be the same, but Invoke is only necessary if the code originates from a background thread.
 
Last edited:
As you say, you only need to use InvokeRequired if you need to determine whether it is required to use Invoke. The way I usually teach people to write code to modify a control from a UI thread is like so:

1. Start with the code you would usually use to update the control directly, e.g.
VB.NET:
Private Sub DoSomething()
    '...'
    
    Label1.Text = "Hello World"
    
    '...'
End Sub
2. Move the control-specific code to its own method and call that method in place of the original code:
VB.NET:
Private Sub DoSomething()
    '...'   

    SetLabel1Text()   

    '...'
End Sub

Private Sub SetLabel1Text()
    Label1.Text = "Hello World"
End Sub
3. Add an If/Else block that tests InvokeRequired and put the original code in the Else block:
VB.NET:
Private Sub SetLabel1Text()
    If Label1.InvokeRequired Then
    
    Else
        Label1.Text = "Hello World"
    End If
End Sub
4. Call Invoke in the If block to invoke the current method on the UI thread:
VB.NET:
Private Sub SetLabel1Text()
    If Label1.InvokeRequired Then
        Label1.Invoke(AddressOf SetLabel1Text)
    Else
        Label1.Text = "Hello World"
    End If
End Sub
There are other, simpler options but they will vary between scenarios. If you follow the pattern above then it will be the same for every scenario and you will never do it the wrong way, so you might use InvokeRequired every time in that case, even if you know that the code will always be initiated from a secondary thread.
 
Back
Top