I put together a little test program to learn about multi threading in VB.net. After a lot of researching, trying and failing I got my program running, at least a bit.

Now it behaves oddly and I can't explain why. Maybe you can tell me, what's wrong with my program, why it behaves the way it does and/or what I have to change to get it working the way it's supposed to work.

My program contains a class (TestClass), that simulates the long running tasks that I want to each execute on a different thread, a progress form (Form1) to show progress messages from my long running tasks and the main procedure, which puts these two together.

Here's my code:

**Progress form** (Form1) containing two listboxes (ListBox1 and ListBox2):

```
Public Class Form1

Public Sub AddMessage1(ByVal message As String)
  If String.IsNullOrEmpty(message) Then
    Exit Sub
  End If

  Me.ListBox1.Items.Add(message)
  Me.ListBox1.SelectedIndex = Me.ListBox1.Items.Count - 1
  Application.DoEvents()
End Sub

Public Sub AddMessage2(ByVal message As String)
  If String.IsNullOrEmpty(message) Then
    Exit Sub
  End If

  Me.ListBox2.Items.Add(message)
  Me.ListBox2.SelectedIndex = Me.ListBox2.Items.Count - 1
  Application.DoEvents()
End Sub

End Class

```

**TestClass**:

```
Imports System.Threading

Public Class TestClass

  Public Event ShowProgress(ByVal message As String)

  Private _milliSeconds As UShort
  Private _guid As String

  Public Sub New(milliSeconds As UShort, ByVal guid As String)
    _milliSeconds = milliSeconds
    _guid = guid
  End Sub

  Public Function Run() As UShort
    For i As Integer = 1 To 20
      RaiseEvent ShowProgress("Run " & i)
      Thread.Sleep(_milliSeconds)
    Next i

    Return _milliSeconds
  End Function

End Class

```

**Main procedure**:

```
Imports System.Threading.Tasks
Imports System.ComponentModel

Public Class Start
  Private Const MULTI_THREAD As Boolean = True

  Public Shared Sub Main()
    Dim testClass(1) As TestClass
    Dim testTask(1) As Task(Of UShort)
    Dim result(1) As UShort

    testClass(0) = New TestClass(50, "Test1")
    testClass(1) = New TestClass(200, "Test2")

    Using frm As Form1 = New Form1
      frm.Show()

      AddHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
      AddHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2

      If MULTI_THREAD Then
        testTask(0) = Task(Of UShort).Factory.StartNew(Function() testClass(0).Run, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext)
        testTask(1) = Task(Of UShort).Factory.StartNew(Function() testClass(1).Run, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext)

        Task.WaitAll(testTask)

        result(0) = testTask(0).Result
        result(1) = testTask(1).Result
      Else
        result(0) = testClass(0).Run
        result(1) = testClass(1).Run
      End If

      RemoveHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
      RemoveHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2

      frm.Close()
    End Using

    MessageBox.Show("Result 1: " & result(0) & "; Result 2: " & result(1))
  End Sub

End Class

```

This program is supposed to open the progress form, run the two long running tasks in parallel, show the progress messages of the two long running tasks, close the progress form when both long running tasks are finished and show a message box with the results of the long running tasks.

Now to the behaviour I can't explain: If I run this program, it shows a "Run 1" in both listboxes, so both tasks started running, but then only the first listbox gets filled and only when the first listbox is filled (the first task completed), the second listbox continues getting filled. So, both tasks get started, but the second one waits for the first one to finish before continuing running.  

But, when I comment out the `Task.WaitAll(testTask)` in my main procedure, it's the other way around. It shows a "Run 1" in both listboxes, then the second listbox gets filled and only when the second listbox is filled (the second task completed), the first one continues running.

Why does my program behaves so oddly and how can I make it run my two tasks at the same time?

Thank you for your help in solving this little mystery :-)

---

**Update**  

Since the only answer so far stated that it has to do with the `SynchronizationContext` I'm using I removed it from the code of my main procedure:

**Main procedure**:

```
Imports System.Threading.Tasks
Imports System.ComponentModel

Public Class Start
  Private Const MULTI_THREAD As Boolean = True

  Public Shared Sub Main()
    Dim testClass(1) As TestClass
    Dim testTask(1) As Task(Of UShort)
    Dim result(1) As UShort

    testClass(0) = New TestClass(50, "Test1")
    testClass(1) = New TestClass(200, "Test2")

    Using frm As Form1 = New Form1
      frm.Show()

      AddHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
      AddHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2

      If MULTI_THREAD Then
        testTask(0) = Task(Of UShort).Factory.StartNew(Function() testClass(0).Run)
        testTask(1) = Task(Of UShort).Factory.StartNew(Function() testClass(1).Run)

        Task.WaitAll(testTask)

        result(0) = testTask(0).Result
        result(1) = testTask(1).Result
      Else
        result(0) = testClass(0).Run
        result(1) = testClass(1).Run
      End If

      RemoveHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
      RemoveHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2

      frm.Close()
    End Using

    MessageBox.Show("Result 1: " & result(0) & "; Result 2: " & result(1))
  End Sub

End Class

```

To avoid an `InvalidOperationException` because of illegal cross-thread calls, I changed the code of my form as follows:

**Progress form** (Form1) containing two listboxes (ListBox1 and ListBox2):

```
Public Delegate Sub ShowProgressDelegate(ByVal message As String)

Public Class Form1

Public Sub AddMessage1(ByVal message As String)
  If String.IsNullOrEmpty(message) Then
    Exit Sub
  End If

  Debug.Print("out List 1: " & message)

  If Me.InvokeRequired Then
    Me.BeginInvoke(New ShowProgressDelegate(AddressOf Me.AddMessage1), message)
  Else
    Debug.Print("in List 1: " & message)

    Me.ListBox1.Items.Add(message)
    Me.ListBox1.SelectedIndex = Me.ListBox1.Items.Count - 1
    Application.DoEvents()
  End If
End Sub

Public Sub AddMessage2(ByVal message As String)
  If String.IsNullOrEmpty(message) Then
    Exit Sub
  End If

  Debug.Print("out List 2: " & message)

  If Me.InvokeRequired Then
    Me.BeginInvoke(New ShowProgressDelegate(AddressOf Me.AddMessage2), message)
  Else
    Debug.Print("in List 2: " & message)

    Me.ListBox2.Items.Add(message)
    Me.ListBox2.SelectedIndex = Me.ListBox2.Items.Count - 1
    Application.DoEvents()
  End If
End Sub

End Class

```

I just added a few Debug.Prints for debugging and the `InvokeRequired` parts.

Now both tasks run parallel (I know because of the `Debug.Print` calls with the "out List" messages) but my progress messages don't show in the listboxes, the according code never gets executed (the `Debug.Print` calls with the "in List" messages don't get shown in the debug window).

I googled for the right way to do the `InvokeRequired` part and the way I did it seems to be right, but it doesn't work.  

Can someone please tell me, what's wrong?

Thank you again for your help.