Example of multi thread for newbies in visualbasic
Multithread, multi-thread, multi-tasking�. Anyway all means the same thing. Is a program that could do many things at the same time to make your program faster. With ordinarily program, everything is done sequentially.
If you read this article, is because you want to make your programs faster, you want your program to be able to do 2 things at the same time or simply interested to know how your program could use multi-core processor.
Is very important to say right now the concept is not for beginner at the first place. This is more like for intermediate level. But I will try to give the best for a newbie or for a starter.
You could immediately download the sample if you don�t want any explanation at the end of this article. I will separate this post into 2 sections: regular programming and programming with threading (multi-thread).
.
.
Regular programming.
In early days, programs and computers instructions where send one by one in order. Everything was extremely predictable. Each line code was executed one after another.
[Image tik tak too]
In the sample program included in this article, you will have a form with a big loop that fills a listview. Is not important what the ListView is. Is only important to know that when the loop runs, the program use all the resource available to run the loop. The form will because inaccessible. If you try to click on the form, you might see (program not responding).
[Image red form]
If you press the button2, the program will fill the listview and it might take 30 seconds before your form become accessible. The bottom left button won�t respond while the loop is running.
Here is a sample of the code for the first program form1 with no threading:
[Code for form1]
Public Class Form1 #Region "members" Private WithEvents ListView1 As System.Windows.Forms.ListView
#End Region Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Init() Me.Text = "no Threading" Me.BackColor = Color.Red
Dim oForm2 As New Form2 'this line is not good practice oForm2.Text = "with threading" oForm2.BackColor = Color.Green oForm2.Show() End Sub
Private Sub Init() 'ListView1 = New System.Windows.Forms.ListView Dim index1 As Integer
ListView1 = New ListView With ListView1 .Location = New System.Drawing.Point(20, 14) .Name = "ListView1" .Size = New System.Drawing.Size(393, 254) .TabIndex = 3 .UseCompatibleStateImageBehavior = False .View = View.Details .GridLines = True .Scrollable = True .MultiSelect = True .FullRowSelect = True End With For index1 = 0 To 100 Step 1 ListView1.Columns.Add("Title: " & index1.ToString) Next
With Button1 .Text = "change title" End With
Me.Controls.Add(listView1) End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Me.Text = Me.Text & " hello you!" End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click Dim lvi As ListViewItem Dim index1 As Integer Dim index2 As Integer Dim str() As String Dim rdn As New Random ReDim str(ListView1.Columns.Count)
For index1 = 0 To 1000 Step 1 For index2 = 0 To ListView1.Columns.Count Step 1 str(index2) = rdn.Next & rdn.Next & rdn.Next & rdn.Next Next lvi = New ListViewItem(str) ListView1.Items.Add(lvi) Next
End Sub End Class
|
And here is the form layout from the form designer of Visual Studio 2010:
In button2.click there is a big loop that steals all the program resources. When the loop ends, others events will work.
.
.
Multi-thread programming.
I take exactly the same programming and simply converted to a multi-thread program. Is very simple that way I present it to you. I did it on purpose. Let me remind you that you could download directly the code sample of this article or try to follow and understand my explanation. Remember that is not easy for newbies, but if you are reading this, is because you show some interest in this subject.
.
.
Step 1 for multi-threading: take all your big code and put it in a new function.
In the form 1, button2 contain a big code. If the user clicks on button2 from form1, it will run a big code for 30 seconds. Now I am asking you to isolate the code. Cut and paste all that big code in a new function or sub. Name it anything you want, is not important. But in my example, I called it: �ListView_Working�
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
'Step 1 ListView_Working()
End Sub
''' <summary> ''' will work in backgroud ''' </summary> ''' <remarks></remarks> Private Sub ListView_Working() Dim lvi As ListViewItem Dim index1 As Integer Dim index2 As Integer Dim str() As String Dim rdn As New Random ReDim str(ListView1.Columns.Count)
For index1 = 0 To 100 Step 1 For index2 = 0 To ListView1.Columns.Count Step 1 str(index2) = rdn.Next & rdn.Next & rdn.Next & rdn.Next Next lvi = New ListViewItem(str)
ListView1.Items.Add(lvi) ' don't need anymore (Step 2) Next
End Sub
|
To end this first step, you need to call your function from the button2 of form2. In other words, you are simply clean your code and putting all the big code elsewhere.
If you run your code now, your code should 100% the same way than before. Again, this is the first step.
.
Step 2: Create the thread
Let me remind you that on step 1, you isolated the code in another function but nothing really changes in your program. All the shit is still the same. I know but you have to do it if you want to survive at this introduction.
Now you have to create the thread. A thread is an object. You could create the thread ANYWHERE you want in your form, is not important because it will work. If you create it in a sub or function, it will work for sure at 100%, but I would not recommend it. Since this is an introduction for newbies, I rather show it the good way. I suggest you to create it in your form but outside any sub or function. In the code from form2, I created a private thread called : ListView_Working_Thread . [xxxxx]
Public Class Form2 #Region "members"
Private ListView_Working_Thread As Threading.Thread 'Step 2
#End Region
. . . . . [�]
|
It is really not important for new to declare your thread public or private. It is really up to you. The thread is an object like any other object.
Now, if you run your program now, nothing will change. Is the same garbage and it acts identically like form1. I know, I know. But it is important to do this step, because you need the thread. The thread will exist somewhere in your computer and will do as you say in the next step.
I am sorry if my English is not that good. I am trying to use significant tile to describe my ideas in my own comprehension.
.
.
Step 3: merge the thread and the function
Ok. Go in the button2 click event. Notice that there is simply one line : ListView_Working.
That is the name of the function that calls your big code. Now you need to do 1 thing: PUT THE FUNCTION IN THE THREAD.
Is this logic for you??????? You want the big working code running independently from all the rest of your program.
Please observe and try to understand the next code. Compare it with the previous one.
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
'Step 1 'ListView_Working()
'Step 3 If ListView_Working_Thread Is Nothing Then ListView_Working_Thread = New Threading.Thread(AddressOf ListView_Working) ListView_Working_Thread.IsBackground = True ListView_Working_Thread.Start() End If
End Sub
|
The previous code is a suggestion; you could put more line to improve the quality and more security.
Step 4: Using the Invoke command
Now if you run your code right now, you will have an error right here:
Private Sub ListView_Working() Dim lvi As ListViewItem Dim index1 As Integer Dim index2 As Integer Dim str() As String Dim rdn As New Random ReDim str(ListView1.Columns.Count)
For index1 = 0 To 5000 Step 1 For index2 = 0 To ListView1.Columns.Count Step 1 str(index2) = rdn.Next & rdn.Next & rdn.Next & rdn.Next Next lvi = New ListViewItem(str)
ListView1.Items.Add(lvi) 'Problem here Next
End Sub
|
System.InvalidOperationException was unhandled
Cross-thread operation not valid: Control 'ListView1' accessed from a thread other than the thread it was created on.
This error is normal because your thread can�t not access to your �main� program. You separated it from your main program so both functions could run independently, but of course, you need them to work together. Then how could you make all threads works together? Well you can�t. You can�t separate 2 things in parallel and put them in sequence at your convenience. But you could do some small thing. Of course, the more your get good, the more you learn of new tools. Remember this suppose to be for beginners.
Your need to change the regular command line instruction to a invoke. What is invoke? For the moment, we don�t know. We just need to correct the error.
To correct the Invalid Operation you need 2 lines! Yes, only 2 lines.
First, you need to declare a special function using the keyword Delegate. Again, is not important to know what delegate means. Write something like this inside your class but outside your sub and functions.
Public Class Form2 #Region "members"
Private ListView_Working_Thread As Threading.Thread 'Step One Private Delegate Sub ListView_Add_Delegate(ByVal lvi As ListViewItem) 'Step 3
#End Region
. . . [�]
|
Then comment or delete the line with the error and replace it like for a new line of code using the Invoke function.
'ListView1.Items.Add(lvi) ' don't need anymore (Step 2) Me.Invoke(New ListView_Add_Delegate(AddressOf ListView_Add), lvi)
|
Now if you run the code, you will be able to whatever in the form while the big code that calculates a lot of stuff is working. Never the background program will interrupt the form.
Your final code would look like this for form2.
''' <summary> ''' This is a sample from Check Technologies lt�e ''' http://checktechno.ca ''' </summary> ''' <remarks></remarks> ''' Public Class Form2 #Region "members" Private WithEvents ListView1 As System.Windows.Forms.ListView Private ListView_Working_Thread As Threading.Thread 'Step One Private Delegate Sub ListView_Add_Delegate(ByVal lvi As ListViewItem) 'Step 3
#End Region Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Init() End Sub
Private Sub Init() 'ListView1 = New System.Windows.Forms.ListView Dim index1 As Integer
ListView1 = New System.Windows.Forms.ListView With ListView1 .Location = New System.Drawing.Point(20, 14) .Name = "ListView1" .Size = New System.Drawing.Size(393, 254) .TabIndex = 3 .UseCompatibleStateImageBehavior = False .View = View.Details .GridLines = True .Scrollable = True .MultiSelect = True .FullRowSelect = True End With For index1 = 0 To 100 Step 1 ListView1.Columns.Add("Title: " & index1.ToString) Next
With Button1 .Text = "change title" End With
Me.Controls.Add(ListView1) End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Me.Text = Me.Text & " hello you!" End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
'Step 1 ListView_Working()
'Step 2 If ListView_Working_Thread Is Nothing Then ListView_Working_Thread = New Threading.Thread(AddressOf ListView_Working) ListView_Working_Thread.IsBackground = True ListView_Working_Thread.Start() End If
End Sub
'this is not enought Private Sub ListView_Working_old() Dim lvi As ListViewItem Dim index1 As Integer Dim index2 As Integer Dim str() As String Dim rdn As New Random ReDim str(ListView1.Columns.Count)
For index1 = 0 To 9000 Step 1 For index2 = 0 To ListView1.Columns.Count Step 1 str(index2) = rdn.Next & rdn.Next & rdn.Next & rdn.Next Next lvi = New ListViewItem(str) ListView1.Items.Add(lvi) Next
End Sub
''' <summary> ''' will work in background ''' </summary> ''' <remarks></remarks> Private Sub ListView_Working() Dim lvi As ListViewItem Dim index1 As Integer Dim index2 As Integer Dim str() As String Dim rdn As New Random ReDim str(ListView1.Columns.Count)
For index1 = 0 To 5000 Step 1 For index2 = 0 To ListView1.Columns.Count Step 1 str(index2) = rdn.Next & rdn.Next & rdn.Next & rdn.Next Next lvi = New ListViewItem(str)
'ListView1.Items.Add(lvi) ' don't need anymore (Step 2) Me.Invoke(New ListView_Add_Delegate(AddressOf ListView_Add), lvi) 'step 4 Next
End Sub
''' <summary> ''' this is step 4 : Invoke ''' </summary> ''' <param name="lvi"></param> ''' <remarks></remarks> Private Sub ListView_Add(ByVal lvi As ListViewItem)
ListView1.Items.Add(lvi)
End Sub
End Class
|
Step 5: improve performance
This is where my article ends. I will try to write more details.
You will notice that the listview will always call for the refresh or the repaint screen making your program slower. Yes I know is not logic for now. Well you need to do more things to make your program fun to use. But of course, this is an example and everything here is on purpose.
If you like this post, please comment it or share it.