In this article I will try and give you an example of one of
the most exciting new feature of VB.NET… Free threading! Take a look the
following VB6 code:
Dim myTest as Ctest
Public Function TestFunction(Id as Integer) as Integer
Dim Ret as Integer
Set myTest = New Ctest
Ret =
MyTest.DoSomething(Id)
TestFunction = Ret
Set myTest = Nothing
End Function
What happens here is very simple. We have a class (Ctest)
which contains a method called: DoSomething. The DoSomething method takes one
argument (Id) and returns an integer. The above piece of code wraps all this
neatly in a function. I am sure you’ve done something like this a million times
before.
Now what happens when DoSomething is a method that runs for
a very long time? Let’s say it iterates through an ADO Recordset containing a
thousand records? Right! Your code is going to hit the line:
Ret =
MyTest.DoSomething(Id)
…And wait till the DoSomething method is done before your
code will continue with the line below it (the one that sets TestFunction to
the return value of DoSomething). While this is acceptable in most cases, for
instance if DoSomething was to contain the code that saves a long document and
the user has to wait anyway, it is very annoying behavior in a lot of other
cases. I have tried every trick in the book, but VB6 doesn’t have a neat way of
handling this situation. At some point your code will be waiting for other code
to finish. If you ever tried keeping the GUI responsive with DoEvents while
your application is off to do some expensive database operation, you will know
exactly what I mean.
VB.NET to the rescue! Enter stage left, FREE THREADING.
Wouldn’t it be great if you had a way to tell VB that you really don’t need to
wait but instead want to go on with whatever the next task of your code is? You
can!
The trick is in:
System.Threading.Thread
The system.threading namespace allows you to push methods of
a class or subs and functions of your regular code off to its own thread.
Create a form with a button on it called Button1. Then…
‘the following goes under the Inherits portion of your VB code
Dim Test as New Ctest
Dim ThreadTest as System.Threading.Thread(AddressOff
MyThreadTest)
‘this is a simple Sub:
Public Sub MyThreadTest
Test.DoSomeThing(Id)
End Sub
‘this is the button’s click event
Private
Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
MsgBox("Beginning New Threads")
ThreadTest = New
System.Threading.Thread(AddressOf _ MyThreadTest)
ThreadTest.Start()
MsgBox(“Done”)
End
Sub
Do NOT run this code! IT WILL FAIL. There is a couple of
things we still need to do, but the above part shows us what is going on when
we get into multi-threading. So what the heck is going on??
The first line we simply set a reference (Dim) to our Ctest
class (remember? The one with the very loooooong running method.) In the next
line we simply tell VB to declare a new thread! That is really most of what
there is to it. By saying “Dim <somename> as new
System.Threading.Thread(AddressOf <somemethod>)” We have created a new
thread to call a method/sub on. The AddressOf operator might be a surprise to
you. What you are doing there is saying to VB “Hey when I start doing something
on that new thread I want you to be doing <insert name of method/sub>”.
Some people might now say that I am over simplifying this… I AM! But for now
that is all you need to know.
You can see that I pointed the thread to a Sub
(AddressOf MyThreadTest ‘MyThreadTest
is a Sub) and not directly to the class we are using. There is a very good
reason for that. If you want anything to run in its own thread you can’t pass
arguments, or receive return values. I know what you are thingking…. “Geez,
that’s not very useful!” But think about it for a second. You are telling VB to
start a new thread… A NEW THREAD! Not a new instance of a class, not another
copy of an ActiveX Server… A NEW THREAD! You completely disconnected the code
on that thread from the main application. The application you’re doing this in
doesn’t know anything about this new thread, and quite frankly, it doesn’t give
a rodent’s butt-cheek. That is why you we need to wrap that code into a sub
that our application DOES know about and that is exactly what I am doing this
piece of code:
Public Sub MyThreadTest
Test.DoSomeThing(Id)
End Sub
I set my new thread to be: AddressOf MyThreadTest. Even
though The Sub doesn’t take any arguments or returns anything, I can have the
call to the Ctest class inside of it take an argument (Id). Oh! This is why I
said not to run it yet previously. VB.NET will complain that it doesn’t know “Id”.
For testing purposes we can quickly fix this. Change the code of the Sub
MyThreadTest to read:
Public Sub MyThreadTest
Dim Id as Integer
Id = 10
Test.DoSomeThing(Id)
End Sub
Of course to run all this you better create a class in your
project called Ctest with a DoSomething Function that takes an Integer (Id) as
an argument, but you get the idea.
The last code in your project is the Click event of the
button I had you put on the form. The most important line of code inside it is:
ThreadTest.Start()
See what we are doing here is not calling the Sub MyThreadTest.
Instead we are saying: I declared a thread called ThreadTest, Start it! Because
we previously set the ThreadTest to be AddressOf MyThreadTest, VB will now run
the code inside that Sub in its own thread.
To get the full effect of this you should really add a class
called Ctest to your project and create a DoSomething function in it that does
something that takes very very very looooong. If you’ve done that, start the
application and click on the button. What you will see is the first message box
reading: Beginning New Threads. If you on OK, the code will jump into the Sub
MyThreadTest. But rather then waiting for execution of this Sub (and the call
to the Ctest method DoSomething inside it) it will almost immediately show the
next message box (“Done!”). And THAT is free threading in a nutshell… Cool or
what??