Multi-Threading and Delegates Tutorial in VB .NET

This guide will show you everything you need to create a non-GUI multi-threaded application in VB .NET.

There are 2 ways of using multi-threading in VB .NET. First by making use of delegates which I will explain here. And second by programming the threads manually (not actually more complicated).

Using delegates, .NET helps simplify the entire process of using a separate thread and saves you from having to manage the parameter passing, result retrieving and timing issues.

First to simply call a method on a separate thread with a parameter

Delegate Function MyDelegate(ByVal text as String) as String
Function PrintStuff(ByVal text as String) as String
    Return "Success"
End Function
Sub Main()
    Dim d as MyDelegate = AddressOf PrintStuff
    d.BeginInvoke("hello world", Nothing, Nothing)
    'I can do more stuff here
End Sub

Here we have a Main thread and a second thread to print some stuff. Also, a delegate with the same signature as the function we want to run (PrintStuff) already exists. Very simply, the Main thread creates a delegate that points to PrintsStuff and calls for the delegate to start executing PrintStuff on a separate thread. A parameter is passed to PrintStuff in the process and Main can continue working while PrintStuff is busy.

Now suppose you want to know when PrintStuff finishes because you want the result “Success”. We can do this by the use of a callback function.

First, we create the callback function

Sub MyCallback(ByVal result as IAsyncResult)
    Console.WriteLine("Now I know PrintStuff finished")
End Sub

Then we make sure the callback function gets called by changing the previous BeginInvoke command to

d.BeginInvoke("hello world", New AsyncCallback(AddressOf MyCallback), Nothing)

In other words, the before last parameter (depending on how many parameters your MyDelegate is supposed to take, since they come in front) is where you specify your callback function. Now MyCallback will be called when PrintStuff is done (ie after about 5 seconds)

Now we need MyCallback function to actually read the return of PrintStuff (“Success”). It is contained in the IAsyncResult.

Sub MyCallback(ByVal result as IAsyncResult)
    Console.WriteLine("Now I know PrintStuff finished")
    Dim resultClass = CType(result, AsyncResult)
    Dim d as MyDelegate = CType(resultClass.AsyncDelegate, MyDelegate)
    Console.WriteLine("And I also know that the result is: " & d.EndInvoke(result))
End Sub

In other words, (instance of MyDelegate).EndInvoke will give you the return of PrintStuff. You could have simply called it in your Main instead of MyCallback, but then Main will remain on that line until PrintStuff reaches its Return line, defeating the whole purpose of multi-threading. When you use EndInvoke in the callback function, you are guaranteed that PrintStuff has already reached its Return line and you simply have to retrieve the result.

For multi-threading applications involving GUI elements, check by other tutorial to see how to avoid illegal cross-thread operations.

  • Hi. Really nice post . It’s really useful

  • wim

    Dim resultClass = CType(result, AsyncResult)

    gives an error in vs2010!!

  • Abc

    Thread.Sleep(5000) error 2010threading.Thread.Sleep(5000)

  • Umer Saleem

    Wow! +1…! 😉

  • Lazarus

     The best post for using threads with callbacks,  function return value and  procedure.
    Thanks a lot

  • Sjit Knight

    Imports System.Threading

  • Jasper John Cinatad


    Imports System.Runtime.Remoting.Messaging

  • Alex

    So long ago and so useful. I’ve found so many complicated examples everywhere.

  • wahab


    I have calling the function by

    Dim d As getrichlengthmain

    d = AddressOf getrichlenghtdele
    d.BeginInvoke(FstList, New AsyncCallback(AddressOf MyCallback), Nothing)

    dim resultvalue as string

    resultvalue= d.EndInvoke()

    and i want to return the value from function how I can get that.

    my function code is

    Private Delegate Function getrichlengthmain(ByVal TB As RichTextBox) As String

    Private Function getrichlenghtdele(ByVal TB As RichTextBox) As string

    Return TB.Lines.Length

    End Function

    Mycalback sub is

    Sub MyCallback(ByVal result As IAsyncResult)
    ‘Nothing here
    End Sub

    Waiting for your reply.

    Very thanks

  • Republica Dominicana

    i, great post ones question how i can do that between classes? for example i have one function in my class utility and i want to invoke as multi-threaded?

  • Nocardium

    Nice tutorial. I like the way you actually went back to basics to demonstrate the point without going straight to something that’s already too complicated like sockets or API calls.

    I might be being really stupid, but I still can’t get my head around some of the concepts. Can I ask why the callback function creates another instance of the initial delegate? And also, how come you don’t need to send the IAsyncResult manually when calling the callback subroutine?

    Feel free to laugh hysterically at my ineptitude if these are completely stupid questions.