Thread ID Invoke......

Johnson

Well-known member
Joined
Mar 6, 2009
Messages
158
Programming Experience
Beginner
So here we can see we e back ground thread ID and then invoke the UI thread ID

VB.NET:
    Private Sub SomeMethod(ByVal SomeValue As Integer)
        Debug.WriteLine(Thread.CurrentThread.ManagedThreadId)

        If Me.InvokeRequired Then
            Me.Invoke(New Action(Of Integer)(AddressOf SomeMethod), SomeValue)
        Else
            Debug.WriteLine(Thread.CurrentThread.ManagedThreadId)
        End If
    End Sub

But here we are always on the same thread ID. why?

VB.NET:
    Private Sub SomeThread()
        For i As Integer = 0 To 10000
            Debug.WriteLine(CStr(Thread.CurrentThread.ManagedThreadId))
            SomeThreadHandler(i)
            Debug.WriteLine(CStr(Thread.CurrentThread.ManagedThreadId))
        Next
    End Sub

    Private Sub SomeThreadHandler(ByVal value As Integer)
        Invoke(New MethodInvoker(Sub()
                                     Me.Text = value.ToString
                                 End Sub))
    End Sub
 
Because you are only writing the thread ID in code that's executed on the secondary thread. The only part of that code that's executed on the UI thread is the part in the lambda expression. That's where you need to write the thread ID if you want to see that it's executed on the UI thread:
VB.NET:
    Private Sub SomeThread()
        For i As Integer = 0 To 10000
            Debug.WriteLine(CStr(Thread.CurrentThread.ManagedThreadId))
            SomeThreadHandler(i)
            Debug.WriteLine(CStr(Thread.CurrentThread.ManagedThreadId))
        Next
    End Sub

    Private Sub SomeThreadHandler(ByVal value As Integer)
        Invoke(New MethodInvoker(Sub()
                                     Me.Text = value.ToString
                                     [B][U]Debug.WriteLine(CStr(Thread.CurrentThread.ManagedThreadId))[/U][/B]
                                 End Sub))
    End Sub
 
Oh silly boy. Blame drink lol. Iv read the documentation but still not 100% sure. which would be the preferred method. Invoke, Action(Of T delegate or SynchronizationContext class? Might seem silly to you but i just cant make sense of it. I always use Action(of T but then saw a post by you on another forum using the SynchronizationContext class.
 
As is usually the case, there are some "rules" you can follow so that you know what to use in each particular case.

1. If your code is in a Windows Form, use the InvokeRequired and Invoke members of that form or an appropriate control. If you're in a WPF Window then use the equivalent, which is the Dispatcher property. Otherwise, use the SynchronizationContext class.
2. If you're using InvokeRequired and Invoke in a WinForms app, always use a MethodInvoker delegate if the method you're invoking has no parameters and no return value. Otherwise, use the appropriate Action or Func delegate.

Point #1 is because the SynchronizationContext is going to use one of the two aforementioned methods under the hood anyway, so you should only accept the overhead if you don't already have access to an appropriate control yourself. Point #2 is because the MethodInvoker is always going to be more efficient than any other delegate and the Action and Func delegates are intended to be general-purpose. You could declare your own delegate if you wanted to but I'd only suggest that if it was going to be exposed beyond the assembly it's declared in.

Can I assume that this is the thread of mine you're referring to:

Accessing Controls from Worker Threads
 
As is usually the case, there are some "rules" you can follow so that you know what to use in each particular case.

1. If your code is in a Windows Form, use the InvokeRequired and Invoke members of that form or an appropriate control. If you're in a WPF Window then use the equivalent, which is the Dispatcher property. Otherwise, use the SynchronizationContext class.
2. If you're using InvokeRequired and Invoke in a WinForms app, always use a MethodInvoker delegate if the method you're invoking has no parameters and no return value. Otherwise, use the appropriate Action or Func delegate.

Point #1 is because the SynchronizationContext is going to use one of the two aforementioned methods under the hood anyway, so you should only accept the overhead if you don't already have access to an appropriate control yourself. Point #2 is because the MethodInvoker is always going to be more efficient than any other delegate and the Action and Func delegates are intended to be general-purpose. You could declare your own delegate if you wanted to but I'd only suggest that if it was going to be exposed beyond the assembly it's declared in.

Can I assume that this is the thread of mine you're referring to:

Accessing Controls from Worker Threads

Ok that cleans it up a little. I wont be using SynchronizationContext class any time soon then. Will stick to raising events in a long running task and catch them on the form and invoke using the correct delegate.

I have read that article which help loads. This was the thread i was speaking about. Alternatives to the BackgroundWorker?-VBForums
 
Ok just to finalize. So i would never update the UI like this from a secondary thread.

VB.NET:
Imports System.Threading

Public Class AsyncMethod
    Private m_context As SynchronizationContext = SynchronizationContext.Current
    Private m_data As String

    Public Event SomeData As EventHandler(Of SomeData)

    Public Sub DoSomething()
        Dim t As New Thread(AddressOf DoSomethingCore)
        t.IsBackground = True
        t.Start()
    End Sub

    Private Sub DoSomethingCore()
        ' Some Long task
        Threading.Thread.Sleep(3000)
        Me.m_data = "Some data passed"
        Me.m_context.Post(AddressOf RaiseSomeData, Nothing)
        Threading.Thread.Sleep(3000)
        Me.m_data = "Some more data passed"
        Me.m_context.Post(AddressOf RaiseSomeData, Nothing)
    End Sub

    Private Sub RaiseSomeData(ByVal o As Object)
        Me.OnSomedata(New SomeData(Me.m_data))
    End Sub

    Protected Overridable Sub OnSomedata(ByVal e As SomeData)
        RaiseEvent SomeData(Me, e)
    End Sub

End Class

MainForm

VB.NET:
Imports System.Threading

Public Class MainForm

    Private WithEvents m_asyncMethod As AsyncMethod

    Private Sub SomeLongTaskButton_Click(ByVal sender As System.Object,
                                         ByVal e As System.EventArgs) Handles SomeLongTaskButton.Click

        Me.m_asyncMethod = New AsyncMethod
        Me.m_asyncMethod.DoSomething()
    End Sub

    Private Sub Data(ByVal sender As Object,
                     ByVal e As EventArgs) Handles m_asyncMethod.SomeData
        Me.datTextBox.Text = DirectCast(e, SomeData).DataValue
    End Sub
End Class

The class would be more like this...

VB.NET:
Imports System.Threading

Public Class AsyncMethod
    Private m_data As String

    Public Event SomeData As EventHandler(Of SomeData)

    Public Sub DoSomething()
        Dim t As New Thread(AddressOf DoSomethingCore)
        t.IsBackground = True
        t.Start()
    End Sub

    Private Sub DoSomethingCore()
        ' Some Long task
        Threading.Thread.Sleep(3000)
        Me.m_data = "Some data passed"
        Me.OnSomedata(New SomeData(Me.m_data))
        Threading.Thread.Sleep(3000)
        Me.m_data = "Some more data passed"
        Me.OnSomedata(New SomeData(Me.m_data))
    End Sub


    Protected Overridable Sub OnSomedata(ByVal e As SomeData)
        RaiseEvent SomeData(Me, e)
    End Sub

End Class

and the MainForms handler

VB.NET:
Imports System.Threading

Public Class MainForm

    Private WithEvents m_asyncMethod As AsyncMethod

    Private Sub SomeLongTaskButton_Click(ByVal sender As System.Object,
                                         ByVal e As System.EventArgs) Handles SomeLongTaskButton.Click

        Me.m_asyncMethod = New AsyncMethod
        Me.m_asyncMethod.DoSomething()
    End Sub

    Private Sub Data(ByVal sender As Object,
                     ByVal e As EventArgs) Handles m_asyncMethod.SomeData
        If Me.datTextBox.InvokeRequired Then
            Me.datTextBox.Invoke(New Action(Of Object, EventArgs)(AddressOf Data), sender, e)
        Else
            Me.datTextBox.Text = DirectCast(e, SomeData).DataValue
        End If
    End Sub
End Class
 
Back
Top