# VBForums CodeBank > CodeBank - Visual Basic .NET >  Understanding Multi-Threading in VB.Net

## Niya

Some time ago I was inspired to write an article here about Lambdas and Delegates after observing a couple of posts where members voiced their misunderstanding of them. It seemed quite helpful to a couple of people and now I'm inspired yet a again to write about another troubling area in the .Net world, *multi-threading*. In this article I hope to be able to take someone who's only heard about it from the depths ignorance about it to being able to competently command their processor's cores to do what they were made to do, share the burden of executing one or more tasks simultaneously.

*Lets Begin*

*Background*

To understand what multi-threading is you must first understand what happens when you run an executable program on an operating system. The OS loads the executable program into memory and the processor executes its code line by line. However with this simple logic one will realize that eventually the lines will run out and the program will end but when you open NotePad, it doesn't end until you tell it to so what gives ? This is because a program is basically one big loop where the same instructions keep getting executed over and over. The reality is actually far more complex that this but its the underlying idea. When you run NotePad, the program enters one big loop and which basically keeps checking for weather the user typed something or clicked a menu option and then it responds to these inputs by executing other code before returning to the loop. So if you press the letter 'K', the code leaves the loop and executes the code that is responsible to rendering the letter 'K' into NotePad's window. When this code is finished, it returns to the loop where it left off, waiting to process other messages.

Think of the code looking like this:-

vbnet Code:
'    Public Sub Main()        Do            Dim msg As MESSAGE = GetMessage()             If msg IsNot Nothing Then                ProcessMessage(msg)            End If        Loop    End Sub

The loop repeatedly checks for messages(key presses, mouse clicks etc) and when it finds one, it passes it to a procedure that knows how to take action. Its an intriguing design but what happens the action taken by *ProcessMessage* leads to another loop, one which will take several seconds or even minutes ? Eg. You click a hyperlink in Internet Explorer to download a file.

Imagine that this is the code that Internet Explorer calls to download a file:-

vbnet Code:
'    Public Sub DownloadFile(ByVal url As String)         Dim fileSize As Integer = GetFileSize(url)        Dim fileName As String = GetFileName(url)        Dim curPos As Integer = 0         Do While curPos < fileSize            Dim fileData() As Byte              Dim bytesRecd As Integer = GetNextChunk(fileData)            curPos += bytesRecd             appendToFile(fileName, fileData)        Loop     End Sub

Now thats not the actual code but I'd expect the concept to be similar to that, so just imagine that it is. What would happen ? Well notice that *DownloadFile* has a loop which repeatedly gets chucks of the file, so if this file is several gigabytes in size then this loop is going to be executing for quite a while. If clicking the download hyperlink led to that sub being executed by *ProcessMessage* then common sense would dictate that Internet Explorer would not be able to process any more messages until *DownloadFile* has finished executing and returned. This means that Internet Explorer would not respond to anything you do because the main message loop is halted. Visualize it like this:-

vbnet Code:
'    Public Sub Main()        Do            Dim msg As MESSAGE = GetMessage()             If msg IsNot Nothing Then                If msg.MsgType = FILEDOWNLOAD Then                    'imagine msg.Data has the url                    DownloadFile(msg.Data)                End If            End If        Loop    End Sub
*Now I must re-iterate that this is not the actual code that does these things in Windows and IE. Its just to give you an idea of what happens.
*

When *DownloadFile* is called the message loop cannot process additional messages until *DownloadFile* returns. However, we all know that we can download a file, even many files and still browse the internet. How can this be ? This is where multi-threading comes into play.

*What is multi-threading*

While many may take the fact that you can still browse while you have a file downloading in the background for granted, it is in fact multi-threading that gives you this luxury. When you have downloads in progress in Internet Explorer, these downloads are being handled by their own threads and the main browser window is running on a different thread so that each of these tasks can proceed independently. Going back to my earlier illustrations, what happens is that *DownloadFile* is passed off to another thread and returns immediately so the message loop can proceed as normal. Threads are exactly that, threads of execution. So what we have are two loops running at the same time. The reality though is that they are not running at the same time but Windows is actually switching between then very very quickly to give the impression of concurrency. The operating system may execute two lines of code in the message loop and switch to the download loop and execute two lines before switching back or switching to yet another thread doing something else. Note though, that on multi-core systems these two threads can actually be executing at the same time. This is what multi-threading is about, execution separate sections of code seemingly or actually at the same time. So now we come to the fun part, actually doing it which we will begin in the next post.

----------


## Niya

*How its done*

We'll start off simple and then build on it. Let us begin with a simple operation. We are going to use a loop that counts from 1 to 100 to simulate a long running operation like a file download.

Open a new Windows Forms project and place a Button and a Label on *Form1*. Double click the Button to bring up its *Click* event handler then code the event handler as:-

vbnet Code:
'    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click        For i = 1 To 100            Label1.Text = CStr(i)            Threading.Thread.Sleep(200)        Next    End Sub
Execute the program and click the button. You should notice that the UI freezes until the count is actually complete. Notice that while its frozen, the label is not being updated. Why is this ? Well remember the message loop I mentioned in the Backround section of this article ?. Pressing the button executes the count loop so while this loop is running the message loop of the UI cannot execute and process the repaint messages for the label to update itself. The UI also cannot process mouse clicks, and key presses. You cannot even move the window.

Our solution is to pass off the count to another thread to execute so that the UI's message loop remains unhindered. Remember, the UI's message loop is running in its own thread usually called the main thread or the UI thread.

We'll start off by putting our counting operation into a separate sup:-

vbnet Code:
'    Private Sub Count(ByVal Max As Integer)        For i = 1 To Max            Label1.Text = CStr(i)            Threading.Thread.Sleep(200)        Next     End Sub

What we do next is really a matter of preference. Some people elect to use the BackgroundWorker component to do their multi-threading. I'm not going to show that approach. The forum is rich with examples on using the BackgroundWorker and I've always preferred to do my threading directly. This is the direction I'm going to demonstrate.

Now that we have our count in its own sub. Code the Button's *Click* event as:-

vbnet Code:
'    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click        Dim t1 As New Threading.Thread(AddressOf Count)         t1.Start(100)    End Sub
The first line instantiates a new Thread object and passes it the address of the *Count* sub since this is the sub we want to execute on another thread. Its very important to note that here lies a very serious limitation. Only a sub with a single parameter is allowed. Luckily in our example *Count* only has one parameter, the number at which the count should end.

The second line starts the thread. *Start* takes one parameter which it uses to call the sub hence:-

vbnet Code:
t1.Start(100)
Is like:-

vbnet Code:
Count(100)
Only it runs on a different thread from the thread it was called from.

If you have Option Strict On the add this *Count* overload:-

vbnet Code:
'    Private Sub Count(ByVal Max As Object)        If TypeOf Max Is Integer Then            Count(CInt(Max))        End If    End Sub
The reason is because the Thread class's constructor expects the address to a sub that takes one parameter of type object. Option Strict would not allow the address of the *Count* that takes an Integer as its parameter to be used. Now execute the program.

At this point you should be ready to pull out your hair because you would get this error:-


So just what in God's name is happening here ? Don't worry, that error is actually happening to prevent potential disasters. Remember I said that the UI has its own thread ? Well think about it what is the UI ? Its basically every thing to do with what you see. Labels, pictures, text are all UI elements so any control that is responsible for showing these things is a part of the UI. The windows message loop runs in the UI thread and its responsible for dealing with these controls. Its repainting, its responses to key presses and mouse clicks are all the UI's thread is responsible for. Its rather intrusive for another thread to just come out of nowhere and make a change to a control that its not responsible for. How does this foreign thread know what the UI is doing with any give control at any given moment ? It doesn't and if it interferes with a control while the UI was in the middle of making some change to the control then it can really cause some instability in the application if the control ends up in some invalid state. This is why VB.Net prevents us from changing the Label's text from another thread.

The correct way to go about this is for the foreign thread to politely ask the UI's thread to update the Label for us. If the UI's thread is busy when the foreign thread makes the request, the request is simply queued and when the UI's thread is finish whatever its doing, its message loop will move on to process the other messages in the queue which would eventually lead it to the request to execute the code that would change the Label's text.

Start by making a function to change the Label's text:-

vbnet Code:
'    Private Sub SetLabelText(ByVal text As String)        If Label1.InvokeRequired Then            Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)        Else            Label1.Text = text         End If    End Sub
In this sub we call the Label's *InvokeRequired* property to determine if the Label is being accessed in the current sub from the UI thread or another thread. It returns *True* if it was called from a foreign thread.


vbnet Code:
Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)
The above line submits a request to the UI thread to re-run *SetLabelText* but instead of running it on the foreign thread, it would then execute on UI thread. *InvokeRequired* would then return *False* which would execute the Label's text change. This is the key because the UI thread would only execute the sub when its not busy processing some other message.

All that's left now is to change *Count*:-

vbnet Code:
'    Private Sub Count(ByVal Max As Integer)        For i = 1 To Max            SetLabelText(CStr(i))            Threading.Thread.Sleep(200)        Next     End Sub

We use *SetLabelText* to change the Label's text instead of trying to change it directly and viola! We have successfully created a simple multi-threaded application.

One thing remains. Execute the program, click the button and close the form before the count is finished. If you did this in the IDE, you would notice that the program doesn't actually stop. That's because the thread is a foreground thread. Usually, we want a background thread for operations like these. Background threads are terminated when the application terminates which is actually when all foreground threads terminate. The UI thread is a foreground thread and by closing the form we terminate that thread but the application won't terminate because the counter is running on another foreground thread. In this case its undesirable so we must make a change:-

vbnet Code:
'    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click        Dim t1 As New Threading.Thread(AddressOf Count)         t1.IsBackground = True         t1.Start(100)    End Sub

We set *IsBackground* to *True* when we create the thread in the Button's *Click* event handler. Now, the application has only one foreground thread so the application ends when this thread terminates which automatically terminates all background threads.

This is the most basic way to do straight threading in VB.Net. Now there are a couple things I still want to cover like thread pool threads, using threads to create asynchronous methods on classes, and using events to signal when operations on other threads are finished. I'll cover that on a later date in the next post. Until then folks, happy threading !!  :wave: 

Note: The following attachment is the demo project. It was written using VS2008 so you must have VS2008 and later to open it.

----------


## Niya

*Thread Pools*
One other thing I want to discuss are thread pools. As defined by wikipedia:-



> In computer programming, the thread pool pattern (also replicated workers) is where a number of threads are created to perform a number of tasks, which are usually organized in a queue. The results from the tasks being executed might also be placed in a queue, or if the tasks return no result (for example, if the task is for animation).Typically, there are many more tasks than threads. As soon as a thread completes its task, it will request the next task from the queue until all tasks have been completed. The thread can then terminate, or sleep until there are new tasks available.


Stated simply, they are pre-created threads that may be continually recycled to be used by several tasks waiting in a queue. The need for it arises from the fact that creating new threads require some overhead, more so than re-using older threads. Its faster to re-use a thread than it is to create a new one. There are other performance related advantages to using thread pools beside creation overhead. You can read up more on thread pools in general here at wikipedia. Also, read up on thread pools in .Net here.

Those two links provide most of what you need to know about thread pools so I'm not going to spend any more time talking about it. Lets just go straight to using them in VB.Net.

If we were to alter the example I provided in post #2 to use thread pools, what do you think we need to do ? :-

vbnet Code:
'
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        System.Threading.ThreadPool.QueueUserWorkItem(AddressOf Count, 100)
    End Sub

The above is how we would code the Button's *Click* event handler to start the count on a thread pool thread. Bet you didn't expect it would be so simple. In fact, its simpler than creating the thread and assigning it a task ourselves. There is no need to instantiate it and no need to make it a background thread. Thread pool threads are background threads by default in .Net.

The *QueueUserWorkItem* is a shared method of the ThreadPool class. It takes a delegate to a sub that has one parameter of the Object type, just like the *Start* method of the Thread class.

*Multi-Threaded classes*

If you examine my example, I'd expect one to conclude that while it works, it isn't very neat. Personally, I'd never actually do multi-threading like that. What if I needed to change some other property of a control ? What if I needed to alter other controls ? Going with the pattern in the example, I'd have to write a function for *every* property I wish to change on any control because I simply cannot change this property as I've shown, from another thread other than the UI thread. If I wished to change the *Text* property of three different labels to three different values, I'd need a separate function to change each Label's *Text* property.

Changing properties across threads requires a function to check the *InvokeRequired* property before changing the property.

Another problem, what if I needed more than one counter ? Of course, you can simply click the button more than once and it would start multiple counts. But there is a practical problem with that. How do you tell them apart ? What you actually have are several threads running that for all intents and purposes have no identity and this is only magnified when you realize that once a thread pool thread starts, you really have no kind of access to it. It starts and does its thing. You can't peek into it, abort it, pause it, nothing.

Associating a running thread with an instance of a class solves the identity problem. Classes by their very nature have unique identities. If you create say...two TextBox instances and use the *Is* operator to compare them, it would evaluate to False because while they are the same type of class they are unique individuals. They are the same control but they can have different text, different fonts, colours or sizes. It is the same with any class, you can even give them unique IDs in the form of a property if you so desire. In the next post, we would get into creating a multi-threaded class. Stay tuned.  :Smilie:

----------


## Niya

*Writing a multi-threaded class*

For this we are going to use the same count sub but lets make things a little more interesting by changing it into a function that returns a value after its finished.

vbnet Code:
Public Class Counter
     Public Function Count(ByVal Max As Integer) As String
        Dim startTime As DateTime = DateTime.Now
         For i = 1 To Max
            Threading.Thread.Sleep(200)
        Next
         Return "Count took : " + (DateTime.Now - startTime).ToString
    End Function
 End Class

Our *Count* sub is now a function that returns a String that states the amount of time it took to complete.

Now start a new Windows Forms project and add a new code file and within it place the above code. On the Form place a Label and a Button and code the Button's *Click* event handler as:-

vbnet Code:
'
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim cn As New Counter
         Label1.Text = cn.Count(20)
    End Sub

Run the program and click the button. You'd notice, just like the start of our previous project in post #2, you can't do anything until the count is finished. You can't move the form or click anything on it because the UI thread is currently executing the *Count* function so it can't process any mouse or keyboard messages until it is free from *Count*. When *Count* is finished, it returns a value which we display in the label.

Before applying multi-threading to the class I want to address a limitation of functions like the *Start* method of the Thread class and *QueueUserWorkItem* of the ThreadPool class. These methods have a rather annoying limitation of only being able to take the address of functions with only one parameter and Option Strict On would demand this parameter be of the Object type. What if *Count* had more than one parameter ? We would have to write an overload to take one Object parameter and have that overload call the real *Count*, getting the parameter from an object made to hold the parameters as fields or properties. If you were to have other multi-threaded methods in the class then you would have to make a class a for the arguments of each method, and a method overload for each to take a single Object parameter made of one of these classes. In other words you have to create two extra entities(a method and a class) for every method you want to call on another thread. This is really retarded, there is just no excuse for that. MS should and could have made *Start*/*QueueUserWorkItem* more flexible. Thankfully I came up with a one-size fits all solution. One MS could have easily come up with.

Outside of the Counter class add this class:-

vbnet Code:
'
Public Class ThreadExtensions
    Private args() As Object
    Private DelegateToInvoke As [Delegate]
     Public Shared Function QueueUserWorkItem(ByVal method As [Delegate], ByVal ParamArray args() As Object) As Boolean
        Return Threading.ThreadPool.QueueUserWorkItem(AddressOf ProperDelegate, New ThreadExtensions With {.args = args, .DelegateToInvoke = method})
    End Function
     Private Shared Sub ProperDelegate(ByVal state As Object)
        Dim sd As ThreadExtensions = DirectCast(state, ThreadExtensions)
         sd.DelegateToInvoke.DynamicInvoke(sd.args)
    End Sub
End Class

I'm not going to go into the details of how that works because I'll have to explain way too much that has nothing to do with multi-threading at all. I'll just say what it does. Its simply a version of *QueueUserWorkItem* that can take the address of any sub or function and an arbitrary amount of arguments using *ParamArray* so we can call any method with it.

Now going back to our counter class I'd start by adding this function:-

vbnet Code:
'
    Public Sub CountAsync(ByVal Max As Integer)
        ThreadExtensions.QueueUserWorkItem(New Func(Of Integer, String)(AddressOf Count), Max)
    End Sub
Its a kin function to Count that calls Count on a thread pool thread using our special *QueueUserWorkItem*. Now our class has two ways to call *Count*. One is synchronous and one is asynchronous. Notice that we declare the asynchronous one as a sub because it would return immediately after its called hence we cannot get a return value because the count would be taking place on another thread while the calling thread would proceed as normal.

The next thing we want to do is to create a private field in our Counter class:-

vbnet Code:
Private context As Threading.SynchronizationContext = Threading.SynchronizationContext.Current
Think of this object as an anchor into the UI thread. Our asynchronous *Count* would be running on another thread but remember we may want to report progress back to the UI thread by updating labels or progress bars. As demonstrated in post #2, we can't simply alter a control from any thread other than the UI thread so we need this object to submit methods to be executed on the UI thread. The SynchronizationContext class has a *Send* method which takes the address of the function we wish to invoke on the UI thread. *Send* however, suffers from the same limitation like *QueueUserWorkItem*, it can only the address of a function with only one parameter. We address this in the same manner as we did before:-

vbnet Code:
'
    Public Shared Sub ScSend(ByVal sc As Threading.SynchronizationContext, ByVal del As [Delegate], ByVal ParamArray args() As Object)
        sc.Send(New Threading.SendOrPostCallback(AddressOf ProperDelegate), New ThreadExtensions With {.args = args, .DelegateToInvoke = del})
    End Sub
Add the above shared method to the ThreadExtensions class. We will use the above method to execute methods on the UI thread so we can alter controls in the proper thread safe manner.

Ok....so we're practically set. Now we need to set up a way to report the progress of the count and return the function's value. In the earlier example in post #2, we used a function to set the Label's text to reflect a where the count has reached. Now we don't want to have to write a separate function for every control we may wish to alter so a far more agreeable solution would be to raise some kind of event on the UI thread and then we are free to do anything to any control and all controls in the normal way. No need to call *InvokeRequired* to check for thread safety anymore. We pass of that responsibility to our Counter class.

Now, lets get to coding the events. In this I tend to stick to the patterns of setting up events that is used by MS in the .Net Framework. So we start by creating an EventArgs based object:-

vbnet Code:
'
Public Class CountChangedEventArgs
    Inherits EventArgs
     Private _CurrentCount As Integer
    Private _Max As Integer
     Public Sub New(ByVal cc As Integer, ByVal max As Integer)
        _CurrentCount = cc
        _Max = max
    End Sub
    Public ReadOnly Property CurrentCount() As Integer
        Get
            Return _CurrentCount
        End Get
    End Property
    Public ReadOnly Property Max() As Integer
        Get
            Return _Max
        End Get
    End Property
End Class

Place the above class outside of the Counter class.

Now add these lines of code to the Counter class:-

vbnet Code:
'
    Public Event CountChanged As EventHandler(Of CountChangedEventArgs)
    Protected Overridable Sub OnCountChanged(ByVal e As CountChangedEventArgs)
        RaiseEvent CountChanged(Me, e)
    End Sub

Our Counter class now has a *CountChanged* event which we would now raise. Remember, we should raise the event on the UI thread so any code in the event handler would be free to alter controls without worrying about cross-thread calls:-

vbnet Code:
'
    Public Function Count(ByVal Max As Integer) As String
        Dim startTime As DateTime = DateTime.Now
        Dim e As CountChangedEventArgs
         For i = 1 To Max
            e = New CountChangedEventArgs(i, Max)
             If context Is Nothing Then
                OnCountChanged(e)
            Else
                ThreadExtensions.ScSend(context, New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), e)
            End If
             Threading.Thread.Sleep(200)
        Next
         Return "Count took : " + (DateTime.Now - startTime).ToString
    End Function

Change the *Count* sub to the above. We use the ThreadExtensions function we wrote earlier to have the SynchronizationContext object raise the event on the UI thread for us in the case *context* is not Nothing. If *context* is Nothing we simply raise the event in the normal way. I do not understand the SynchronizationContext enough to tell you the circumstances under which it would be Nothing but in the most common scenarios it should have a proper object.

The only thing remaining now is that return value. We simply use another event. Like before we create a new EventArgs object:-

vbnet Code:
'
Public Class CountCompletedEventArgs
    Inherits EventArgs
    Private Dim _message As String
     Public Sub New(ByVal msg As String)
        _message = msg
    End Sub
    Public ReadOnly Property Message() As String
        Get
            Return _message
        End Get
    End Property
 End Class

And add the following to the Counter class:-

vbnet Code:
'
    Public Event CountCompleted As EventHandler(Of CountCompletedEventArgs)
    Protected Overridable Sub OnCountCompleted(ByVal e As CountCompletedEventArgs)
        RaiseEvent CountCompleted(Me, e)
    End Sub

Now we change our *Count* function yet again:-

vbnet Code:
'
    Public Function Count(ByVal Max As Integer) As String
        Dim startTime As DateTime = DateTime.Now
        Dim e As CountChangedEventArgs
        Dim msg As String
         For i = 1 To Max
            e = New CountChangedEventArgs(i, Max)
             If context Is Nothing Then
                OnCountChanged(e)
            Else
                ThreadExtensions.ScSend(context, New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), e)
            End If
             Threading.Thread.Sleep(200)
        Next
         msg = "Count took : " + (DateTime.Now - startTime).ToString
         If context Is Nothing Then
            OnCountCompleted(New CountCompletedEventArgs(msg))
        Else
            ThreadExtensions.ScSend(context, New Action(Of CountCompletedEventArgs)(AddressOf OnCountCompleted), New CountCompletedEventArgs(msg))
        End If
         Return msg
    End Function

Our *Count* function now raises a completed event and passes the return value using the EventArgs object. Our Counter class in now has multi-threaded capabilities.

Now go back to the Form's code and change it to this:-

vbnet Code:
Public Class Form1
    Private WithEvents m_cn As New Counter
     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        m_cn.CountAsync(100)
    End Sub
     Private Sub m_cn_CountChanged(ByVal sender As Object, ByVal e As CountChangedEventArgs) Handles m_cn.CountChanged
        Label1.Text = CStr(e.CurrentCount)
    End Sub
     Private Sub m_cn_CountCompleted(ByVal sender As Object, ByVal e As CountCompletedEventArgs) Handles m_cn.CountCompleted
        MsgBox(e.Message)
    End Sub
End Class

The Form must have a Label and a Button. Run the application and click the button and you should see the count progressing indicated by the label and a message box pop up when the count is done, showing the return value which is the time the count took to complete. So there you have it. A working multi-threaded class. There is a little more I'd like to write on this subject but I'm too near the 15K character limit for this post so I'll have to cut it here. Please feel free to post any questions you may have in the thread. Good luck  :Smilie:

----------


## marniel647

thanks for this post i also having a problem under multithreading. i will wait for your other post regarding multithreading.

----------


## Niya

You're welcome  :Smilie: . The first two posts covers the heart of it. My next post will basically show how you can organize that neatly into classes to create multi-threaded components. It will take what I've already discussed and twist it up a little and it would also cover thread pools. I'll try to get it up within this week.

----------


## marniel647

yeah. but i have a question that running into my mind  :Big Grin: 
why do we use threading.thread.sleep
and what does this bold part do t1.start*(100)*?

sorry for a noob question  :Big Grin:

----------


## Niya

Fair questions. There is nothing wrong with not knowing  :Smilie: 




> why do we use threading.thread.sleep


Thread.*Sleep* suspends the thread. I did it in that example because without it the count would have happened too fast for anyone to see what was happening. It should be noted that there is almost no practical reason to ever use Thread.*Sleep* in real applications. Its great for examples to demonstrate stuff but has no real benefits aside from that.




> what does this bold part do t1.start*(100)*?


Remember I did this:-

vbnet Code:
Dim t1 As New Threading.Thread(AddressOf Count)
That line created the Thread object. The constructor takes the address of the *Count* sub. If you look back you would see that sub *Count* takes one argument, which is the number to count up to before the loop finishes. When you call *Start* it allows you to pass one parameter to whatever sub its expected to execute on a different thread, in this case its *Count*. So:-

vbnet Code:
t1.Start(100)
That tells the thread object to call *Count* passing in *100* to its parameter. In other words it effectively does this:-

vbnet Code:
Count(100)
Except that it runs on another thread. Makes sense ?

----------


## marniel647

> Fair questions. There is nothing wrong with not knowing 
> 
> 
> 
> Thread.*Sleep* suspends the thread. I did it in that example because without it the count would have happened too fast for anyone to see what was happening. It should be noted that there is almost no practical reason to ever use Thread.*Sleep* in real applications. Its great for examples to demonstrate stuff but has no real benefits aside from that.
> 
> 
> 
> Remember I did this:-
> ...


thanks for your explanation now i know much the basic of multithreading 
thank you very much.

----------


## nbrege

> *How its done*
> 
> 
> vbnet Code:
> '    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click        Dim t1 As New Threading.Thread(AddressOf Count)         t1.Start(100)    End Sub



Niya ... can I call a function here instead of a sub?  If so, then how do I get the returned value?

ie.  

```
Dim t1 As New Threading.Thread(AddressOf Count)  'a function that returns a value.
```

----------


## Niya

Well, a return value is the issue here isn't it. With Option Strict Off you can actually use a function with only one parameter but then what's the point. The function is executed on another thread so the thread that started isn't blocked waiting for a return value. The correct way to return a value would be to have the function itself signal its own completion and return a value by using a call back. My preferred approach is to implement the functionality that I wish to multi-thread into a class and use events to signal completion and return results. My reserved post is to write about and demonstrate that very thing. I'll try to get it up on Saturday, do you urgently need this information ?

----------


## nbrege

Saturday would be just fine.  Thanks again...

----------


## nbrege

Still waiting for your next post ...

----------


## Niya

Yea I've already begun writing it. I got the section on thread pool threads already completed. I'm going to complete it today. Hope it doesn't disappoint  :Wink:

----------


## Niya

Updated....Posted the section on thread pools. Only one more section to go.

----------


## marniel647

thanks for the update Niya reading now..  :Big Grin:

----------


## Niya

Ok....I've completed the section on multi-threaded classes. Hope you like it  :Smilie:

----------


## Bullrun96

great update Niya.  I've been having trouble with implementing multi-threaded classes so your write up has been very helpful.  I do have a quick question.  What if I want to cancel the running operation in the middle?

----------


## Niya

Its quite easy. Create a method to do it. In the case of the Counter class example, I'd make a *CancelCountAsync* method. I would then make a private boolean field called *CountAsyncCancelled*. When the *CancelCountAsync* method is called it would simply set our *CountAsyncCancelled* to True. The counter loop would be checking this on every iteration and if its True, we simply raise an event and exit the loop or return from the *Count* function. You could opt to create a cancel type event or use the completed event after adding something to the EventArgs object to indicate that the operation was cancelled.

----------


## Bullrun96

wow that was easy.  It took about 2 minutes to implement a cancel button in your counter example.  I'm actually a little embarrassed that I didn't figure that out  :Blush: .  Thanks for your help Niya.

----------


## Niya

That's understandable. The most natural instinct would be to stop the thread itself but its easy to lose sight of the fact that simply ending the function/sub the thread is running will end the thread itself which is what would essentially happen when a cancel is implemented the way I suggested.

----------


## psoftware

Hello Niya, can you help me in my vb multithreaded application? I need to some help because this argument is a bit hard. I'm making a network application (server/client), and in the server app code I have to use multithreading. First, I made a new class which is composed by Tcp sockets code and some of graphical elements (declared after class declaration, a panel, a picture box and a button). I've declared an TCPlistener too, but It make his work into a BackGround Worker. It is composed by a do-loop cycle, which check for new connections, and when a new connection is coming, it create a new instance of my class... Now the problem it's how to interact with GUI from the class istances... how can i insert graphical elements to the GUI and control them? Thanks for the guide! =)

P.S. Sorry for my bad english!

----------


## Niya

Lemme see if I understand your problem. Are these classes being created on a different thread from the UI thread via the BackGroundWorker ?

----------


## walterwjl

Thanks Niya, I'm working through your samples and are finding it quite enjoyable and very easy to understand, keep up the good work!

----------


## psoftware

> Lemme see if I understand your problem. Are these classes being created on a different thread from the UI thread via the BackGroundWorker ?


Exactly! You understood me!!  :big yellow:  Can you help me?

----------


## Niya

> Thanks Niya, I'm working through your samples and are finding it quite enjoyable and very easy to understand, keep up the good work!


Thanks, I'm glad you found it helpful  :Smilie: 




> Exactly! You understood me!!  Can you help me?


Hmm....Well this is a little tricky. As I've shown in my samples, I like to communicate with the UI thread by raising events on the UI thread.

Now I assume you have the BackgroundWorker component on a Form and in the *DoWork* event, your classes are being created. *DoWork* runs on another thread so classes created there will be on that thread. What you could do is create a constructor for your class that takes a SynchronizationContext object which it could use to raise events on the UI thread. You then create a private field in the Form itself which would hold the SynchronizationContext for the UI thread:-

vbnet Code:
Public Class Form1    Dim context As SynchronizationContext = SynchronizationContext.Current     'Form code End Class

Use that *context* variable when calling the constructor of your class within the *DoWork* event. Observe my samples to learn how to use the SynchronizationContext to raise events on the thread it belongs to.

----------


## psoftware

I tried to implement your guide in my code, but now there's some problems... I created some events and inserted your ThreadExtensions class, but when i try to raise an event (following your guide), context variable is null, and because of this, the event is raised in the background thread..... I inserted a MsgBox(Thread.CurrentThread.ManagedThreadId) in the load handle sub of my main window, and another in the events which I created, and the results are not equals... Why is context variable in null?

----------


## Niya

*context* would be null if you if you called *Current* on a thread without a SynchronizationContext object. You indicated that the object itself is being created on another thread so I'd expect it to be null. When a VB.Net program starts one of the things it does is create a SynchronizationContext for the UI thread. Like I said in my guide, think of it like an anchor. You wish to raise events on the UI thread so you get one from the UI thread by calling SynchronizationContext.*Current* on the UI thread. Since you create your objects on the thread pool thread that the BackGroundWorker uses in *DoWork*, the object's constructor would called on that thread which has no SynchronizationContext object. This is why I said in post #26 to declare it on the Form where the BackGroundWorker resides and create a constructor for your class that can take a SynchronizationContext object and when you create a new object in the *DoWork* event you call that constructor an pass the SynchronizationContext variable you declared on the Form.

----------


## Niya

Here is an example of what I mean:-

vbnet Code:
Public Class WhatEverClass
     Private context As Threading.SynchronizationContext = Threading.SynchronizationContext.Current
     Public Sub New()
     End Sub
     'If this class is being instantiated on a non UI thread
    'call this constructor and pass the SynchronizationContext
    'your self
    Public Sub New(ByVal context As Threading.SynchronizationContext)
        Me.context = context
    End Sub
 End Class

You call that second *Sub New* and pass it a SynchronizationContext object from the UI thread.

This is what your Form code should resemble:-

vbnet Code:
Public Class Form1
    'Obtain the Synchronization object for the UI
    Private context As Threading.SynchronizationContext = Threading.SynchronizationContext.Current
     Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
         Dim wec As New WhatEverClass(context)
     End Sub
End Class

Notice that I pass *context* declared as a private field in the Form, into the object's constructor since *DoWork* runs on another thread.

----------


## psoftware

It's a bit hard because I have to translate and to read and read what you write... Now I understood you and I implemented this code in my project, It works fine. But I noticed only first created class can raise events, some others can't (handles subs aren't called)....In my form class I implemented the AddHandler function to make some functions handle my new class events. I don't understand this thing, It's very strange and make me angry!  :Eek Boom: 
Sorry If I'm doing a lot of questions to you, but It's a bit hard argument and I don't know how to solve this problems. I hope you won't hate me!


P.S. You're the best!

----------


## Niya

Ok lets take this one problem at a time......are you having problems raising the events of the objects you create ?

----------


## psoftware

Mmmmmmh yes!  :Embarrassment:  Some classes, can't raise events, and I don't know why...

This is my DoWork Sub



```
Private Sub ChechConnectionsThread_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles ChechConnectionsThread.DoWork
        While True
            Dim clientuser As New RemoteClient(ClientScreenSettings.TCPlistener.AcceptTcpClient, GenIndex(), context)
            AddHandler clientuser.ClientConnected, AddressOf ClientConnectEvent
            AddHandler clientuser.ClientDisconnected, AddressOf ClientDisconnectEvent
            AddHandler clientuser.ClientScreenChanged, AddressOf ClientSendScreen
            AddHandler clientuser.ClientSessionChanged, AddressOf ClientSessionChanged
        End While
    End Sub
```

and this is one of the events...



```
Private Sub ClientConnectEvent(ByVal sender As System.Object, ByVal e As ClientConnectedEventArgs)
        MsgBox(e.ClientName + "id: " + e.ClientIndex.ToString + " has connected")
End Sub
```


I call the event from classes from this sub


```
RaiseEventConnected()
```



```
Public Sub RaiseEventConnected()
        Dim e As New ClientConnectedEventArgs(_ClientNick, _ClientIndex)
        If context Is Nothing Then
            OnClientConnectedEventArgs(e)
        Else
            ThreadExtensions.ScSend(context, New Action(Of ClientConnectedEventArgs)(AddressOf OnClientConnectedEventArgs), e)
        End If
    End Sub
```

ClientConnectedEventArgs and OnClientConnectedEventArgs are coded like your code... Is there something wrong?

----------


## psoftware

In ClientConnectEvent sub I inserted only the msgbox function to test the raising of the event, there are some other things into it...

----------


## Niya

Whoa  :EEK!:  You do realize that by you can only have one RemoteClient object that way right ?

Every time that loop iterates, the last RemoteClient object you created is up for garbage collection so its no wonder only one is raising events. As far as I see you implemented the threading properly so that's not the problem.

Now, just get your hands dirty and complicate this a little more. Store every new RemoteClient you create in a List(Of T) declared as a private field of the Form. This would ensure that every RemoteClient created in that *While* loop is not lost but have active references:-

vbnet Code:
Public Class Form1    Dim ConnectedClients As New List(Of RemoteClient)     Private Sub ChechConnectionsThread_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles ChechConnectionsThread.DoWork        While True            Dim clientuser As New RemoteClient(ClientScreenSettings.TCPlistener.AcceptTcpClient, GenIndex(), context)            AddHandler clientuser.ClientConnected, AddressOf ClientConnectEvent            AddHandler clientuser.ClientDisconnected, AddressOf ClientDisconnectEvent            AddHandler clientuser.ClientScreenChanged, AddressOf ClientSendScreen            AddHandler clientuser.ClientSessionChanged, AddressOf ClientSessionChanged             ConnectedClients.Add(clientuser)        End While    End Sub End Class

----------


## psoftware

I had already created a list of RemoteClient, but in RemoteClient class.....


VB.NET Code:
Public Class RemoteClient
    Shared WithEvents AllClients As New List(Of RemoteClient)
 End Class

and I add classes to the list only when they send their nickname, in this manner...(then, they raise the connectedclient event)


VB.Net Code:
AllClients.Add(Me)
              RaiseEventConnected()

Is this the problem?

----------


## Niya

It shouldn't be a problem. Actually using a static field to record the connected clients is a very good idea. At this point I'm beginning to believe that your problem isn't related to threading but to some implementation detail elsewhere. Post all the code for the RemoteClient class as well as all the form code where the BackGroundWorker resides.

----------


## psoftware

I made some changes in my code and now events seem to be raised correctly  :Big Grin:  But now can I ask you for another thing?

If I want to call subs from the UI thread to the BackgroundWorker Thread and to the classes?

Thanks for all this Answers!  :Embarrassment:

----------


## Niya

Well what about it ? If you want to call a sub from the UI then you are free to do so. Is there some concern you have with this ?

----------


## psoftware

Ehm.... Should I take the SynchronizationContext from the BackgroundWorker and use it with ScSend sub and my class function?  :Smilie:

----------


## Niya

> Ehm.... Should I take the SynchronizationContext from the BackgroundWorker and use it with ScSend sub and my class function?


Ok, I'm a little lost now  :Confused: . I think you may be misunderstanding something fundamental here though. Tell me what sub you wish to call, what class it belongs to and where you are calling it from. I need some more details, I'm not really clear on what your concern is.





> If I want to call subs from the UI thread to the BackgroundWorker Thread and to the classes?


This statement makes no sense, you don't call subs from somewhere *to* somewhere. I just need you to clarify what you mean  :Smilie:

----------


## Niya

The SynchronizationContext is used to submit methods to run on the thread associated with the context.

In your case, the SynchronizationContext object belongs to the UI thread therefore whenever a method is executing on any other thread and needs to run a method back on the UI thread, it uses the SynchronizationContext's *Send* to do so.

----------


## psoftware

Sorry, but it's a bit hard write in english because it's the first time I do it in a forum, and this is a difficult argument  :Embarrassment: 
I used your ThreadExtensions Class, and now i need to call some subs in RemoteClient classes, which are created in the BackgroundWorker thread, from the UI Thread....(from button click event subs and others). How can I do this?

----------


## Niya

Well classes in the strictest sense aren't really thread specific, running methods are. That means a single class can have many different methods running at the same time on different threads. You can call the class' methods from the UI thread as you call any method. The only problem with this is when your method intends to interact with an object that another method running on another thread is interacting with. In that case you would need to consider some kind of synchronization so that the two threads don't try to access the object at exactly the same time. If such a condition doesn't exist then you can safely call the method from the UI in the normal way.

The only reason we even need a SynchronizationContext with multi-threaded objects is because controls are a special case and need to be manipulated on the thread they were created on(usually the UI thread). When controls aren't involve things become much simpler.

----------


## psoftware

This is exactly what I want...



```
In that case you would need to consider some kind of synchronization so that the two threads don't try to access the object at exactly the same time.
```

How can I do this? I have to call some subs in my RemoteClient class which permits my application to send text to the clients... I call this subs from both threads (UI thread adn BackgroundWorker thread) and It could happen the two threads try to access the sub and the objects used in the sub, at exactly the same time....

----------


## Niya

Well calling the same method multiple times from different threads isn't actually a problem. Running methods are really instances of the methods. What you need to look out for are lines of code that access objects outside the scope of the methods for example a private field.

Consider the following:-

vbnet Code:
Public Class Test     Public Sub Method1()        For i = 1 To 100            Debug.Print(i)        Next    End Sub End Class

You are free to call *Method1* as many times as you want from as many threads as you want. If you called it from one thread the same time another thread calls it, then there would be two different instances of the same method running. There is no danger with this. However, imagine this:-

vbnet Code:
Public Class Test    Private lstNumbers As New List(Of Integer)     Public Sub Method2()         For i = 1 To 100            lstNumbers.Add(CStr(lstNumbers.Count))        Next     End Sub  End Class

Now there is a real problem when calling the above *Method2* more than once from different threads. This is because these different instances of the running *Method2* would be accessing the same list and there is a danger both threads access the list at the same time. The solution would be to synchronize access to the list like this:-

vbnet Code:
Public Class Test    Private lstNumbers As New List(Of Integer)     Public Sub Method2()         For i = 1 To 100            SyncLock lstNumbers                lstNumbers.Add(CStr(lstNumbers.Count))            End SyncLock        Next     End Sub  End Class

*SyncLock* would block if it was called on the same object, in this case *lstNumbers*, on another thread. When that other thread passes its *End SyncLock* then the blocked thread would be allowed to proceed and other calls to *SyncLock* on *lstNumbers* from other threads would be blocked in the same manner until it reaches its *End SyncLock*.

----------


## psoftware

You're the best vb.net programmer I've never seen... How can I say a big thank you?? Thanks to you I managed to fix issues that plagued me for months!!  :Big Grin:

----------


## Niya

Oh its no problem my friend  :Smilie:

----------


## Seventje

Hi!

First of all, thanks for the great tutorial, it's been very very instructive.
And now the question, what would be the procedure to use two buttons and two labels that do the same thing, or in my application they would need both differnt inputs from my I/O system? (I'm quite a newbie to this so maybe it's a stuipid question)

Thanks !

----------


## Niya

Tell me more about what you want to do with the I/O system.

----------


## Seventje

Basicly I want to read inputs from it ("start"), next I would activate outputs to activate relays and put tension on my testprobe, next would be to test the output of the testprobe with analog input channels.

----------


## Niya

Ok, I don't really know too much about relays and test probes but if I understand correctly, these things you speak are I/O devices and you want to process input on one thread and output on another....is this correct ?

----------


## Seventje

No, I want to use two or more threads that execute the same code but use differnt inputs/outputs, thats why I would need more than one variable in those threads, for example:

if input(nc) = 1 then 
activate output0(nc)
end if

Thread number one would use input 0 and thread number two would use input 8, trough the nc variable, same with the output.
Maybe I'm just talking weird, sorry if I am  :Smilie:

----------


## Niya

Oh I see, the real problem is that you want to run the same method on different threads with different parameters. Well in the most basic cases you don't have to do anything special, you can just call the same method more than once each time on a different thread. However, if there is some kind of interaction between them or they are accessing the same resource then we have to cater to it.

Now, what approach are you taking to want to take with this. In this thread I show two forms of doing straight threaded coding. The first one where I show how to simply execute methods from a Form on different thread and the second way was to make a class with asynchronous methods and events that are raised on the UI thread. Which way are you thinking of ?

----------


## Seventje

I would need the second way is that I would need 2 variables for each thread, the number of thread (nc in the example above) and it's "place", since I've been teached to make a process that's secuencial with select case, each thread would be in another step of the process. For example, the fist thread is still on case number 10 and the second thread on case number 35. Is there some other way to make the same thing but easier?  :Smilie: 

And to not complicate things much, yes, they access the same resource, I'm thinking of making some sort of buffer to execute them.

Thanks

----------


## Niya

Ok....I think I kinda get what you're saying now....lets see what you have so far and how we can thread it.

----------


## Seventje

For now I got the following:




> Public Class Counter
>     Private context As Threading.SynchronizationContext = Threading.SynchronizationContext.Current
> 
>     Public Event CountChanged As EventHandler(Of CountChangedEventArgs)
>     Protected Overridable Sub OnCountChanged(ByVal e As CountChangedEventArgs)
>         RaiseEvent CountChanged(Me, e)
>     End Sub
> 
>     Public Sub CountAsync(ByVal paso As Integer)
> ...





> Public Class Form1
> 
>     Private WithEvents m_cn As New Counter
> 
>     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
>         m_cn.CountAsync(20)
>     End Sub
>     Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
>         m_cn.CountAsync2(30)
> ...


I have no idea how to do the same thing with two threads. Thanks in advance !

----------


## Niya

Why do you have two asynchronous *Count* methods ? You do realize you can have one and call it as many times as you want right ? And each one will execute on a separate thread. I don't really see much of a problem here. You have to remember that an executing method is actually an executing *instance* of a method.

----------


## SNiiP3R

Hi,

I have a question. The following Sub from your tutorial takes an address of the Count function with the 'String' as the return type.



```
    Public Sub CountAsync(ByVal Max As Integer)
        ThreadExtensions.QueueUserWorkItem(New Func(Of Integer, String)(AddressOf Count), Max)
    End Sub
```

My question is, is there anyway I can change the code so that it would work with Subs instead of Functions. Since my Connect Sub does not return anything, I don't need it to be a Function ? So,  what I mean is the following:



```
    Public Sub ConnectAsync(ByVal IP As String, ByVal Port As Integer)
        ThreadExtensions.QueueUserWorkItem(New Func(Of String, Integer)(AddressOf Connect), IP, Port)
    End Sub

    Public Sub Connect(ByVal IP As String, Port As Integer)
        'Some code here
    End Sub
```

I have tried something like 'New Sub()' but that obviously did not work. 


Thank you

----------


## SNiiP3R

Okay, I figured it out. Please ignore my previous post. 

Apparently, when we're dealing with Subs that don't return anything we have to use New Action(). So the above Sub would look something like this,



```
    Public Sub ConnectAsync(ByVal IP As String, ByVal Port As Integer)
        ThreadExtensions.QueueUserWorkItem(New Action(Of String, Integer)(AddressOf Connect), IP, Port)
    End Sub
```


I'm still however, not too sure what to do with Subs that have no parameters ? For example,



```

    Public Sub Disconnect()
        ThreadExtensions.QueueUserWorkItem()
    End Sub

    Private Sub sockDisconnect()

    End Sub
```

*New Action()* in this case is not working for some reason.

----------


## Niya

Use the non generic Action delegate type.

vbnet Code:
'
    Public Sub Disconnect()
        ThreadExtensions.QueueUserWorkItem(New Action(AddressOf sockDisconnect))
    End Sub

----------


## soviet87

Niya, I really have to say, by far this is the-best breakdown I have ever seen of multithreading for vb.net. I was having so much issues trying to figure this out for my self. You put this in plain,easy to follow language. I am forever great-full! As you can see it is 5:30AM and I have not been to sleep and I felt the need to register for the forums just to tell you this, thank you very much. :Big Grin:

----------


## Niya

Thank you friend....I'm glad it helped you  :Smilie: 

I thought it might be helpful to try and explain it in the way I would have liked someone to explain it to me when I didn't know how to do it. I seemed to have hit the mark  :Smilie:  Thx

----------


## DaleAlanB

Niya,  Thank you for providing these examples.  I don't know if your still following this thread (as the last post was almost 4 months ago).  However in case you are, would you be so kind as to provide an identical example of your count program without utilizing your ThreadExtensions routine.  I'm using VB2005 and it will not resolve some of the 'With' instructions you used in the routine.  And please don't tell me to upgrade, there are reasons why I'm using VB2005 and .net framework 2.0, which I won't discuss as it is off topic.  Threading is a something I haven't had a need to code until now - so I'm new at it.  Any help would be appreciated.

What I'm trying to do is to create a second thread that runs continuously in an endless loop.  The code in the loop will read about a dozen Boolean values set from the UI thread, and send them out through the serial port to another device (PLC), then turn around and read some other data back from the serial port.  Once the data is read back, it is unpacked and then checked to see if any values have changed since the last read.  If so, I want to raise a 'status change' event on the UI thread and pass to the event what changed (which class instance) and the new property value (which can be set from either thread).  After raising the event (if necessary), the thread will loop back to the beginning and start the communications again (a monitor program).  The UI thread will respond to the event and update the screen accordingly.   I have the communications part working.  I'm trying to work out the threading - your count program pretty much has the functions I need - only I'm unable to use parts of the ThreadExtensions routine as they will not resolve in VB2005.  How else can I do this?

Thanks.

----------


## Niya

Use this one:-

vbnet Code:
Public Class ThreadExtensions
    Private args() As Object
    Private DelegateToInvoke As [Delegate]
     Private Sub New(ByVal delegateArgs As Object(), ByVal delegateInstance As [Delegate])
        Me.args = delegateArgs
        Me.DelegateToInvoke = delegateInstance
    End Sub
     Public Shared Function QueueUserWorkItem(ByVal method As [Delegate], ByVal ParamArray args() As Object) As Boolean
        Return Threading.ThreadPool.QueueUserWorkItem(AddressOf ProperDelegate, New ThreadExtensions(args, method))
    End Function
     Public Shared Sub ScSend(ByVal sc As Threading.SynchronizationContext, ByVal del As [Delegate], ByVal ParamArray args() As Object)
        sc.Send(New Threading.SendOrPostCallback(AddressOf ProperDelegate), New ThreadExtensions(args, del))
    End Sub
     Private Shared Sub ProperDelegate(ByVal state As Object)
        Dim sd As ThreadExtensions = DirectCast(state, ThreadExtensions)
         sd.DelegateToInvoke.DynamicInvoke(sd.args)
    End Sub
End Class

----------


## DaleAlanB

Thanks a bunch Niya.  That works perfectly in VB2005.

Dale

----------


## hondatron

Hi Niya.
i have a small question! Can help me.
example: i have a url: (http://mangafox.me/manga/kingdom_hea...04/c030/1.html). And i wana get comic pictures in this page. Specifically, Downloading 3-4 or more pages in same time to speed up load.  	
only way I solved my problem.

----------


## Niya

In the section where I show how to do multi-threaded classes, I made a class that executed the count on a non-UI thread. In your case you would have a your download method instead of a count. You simply instantiate multiple classes to perform multiple downloads.

----------


## hondatron

thanks Niya.

----------


## junaid89

Hello Niya. Thanks for writing the article. I'm a beginner in VB so I could pickup first 2-3 posts and messed up afterwards.
Actually I have a list of files in my program and need to download 2 files simultaneously and on the completion of a file, it start downloading next in the list. and I'm just confused what to do and how to alter the code..
Will you help me please..

----------


## Niya

Does your problem have to do with multi-threading it or downloading the files ? Have you already got the downloading part working ?

----------


## junaid89

downloading all files in a listbox one by one is not an issue, I used for next loop and it did the job. And also I like to mention that I used:
My.Computer.Network.Download()

I may use Webclient Download Method but thats not an issue at the moment. Multithreading is the issue..

----------


## Niya

Show me the code you're using to download the files.

----------


## junaid89

here it is:


```
        Dim Dir As String = InputBox("Directory", "Dir")
        For i As Integer = 0 To lstLinks.Items.Count - 1


            Dim targetFile As String = lstLinks.Items(i).ToString
            Dim destFile As String

            destFile = "E:\Downloads\" & Dir & "\" & i & ".jpg"


            Try
                My.Computer.Network.DownloadFile(targetFile, destFile, "", "", True, 10000, True, FileIO.UICancelOption.DoNothing)
            Catch ex As Exception
                tbStatus.Text += vbNewLine & "ERROR: File: " & i & " ERR Number: " & Err.Number & ". Description: " & Err.Description & "File Name: " & targetFile
            End Try


        Next
```

----------


## Niya

I'm going to assume you're using VS2010 and later.

The simplest way to achieve what you want would be to put the downloading part in its own sub like this:-

vbnet Code:
'
    Private Sub StartDownloads(ByVal Dir As String)
         For i As Integer = 0 To lstLinks.Items.Count - 1
              Dim targetFile As String = lstLinks.Items(i).ToString
            Dim destFile As String
             destFile = "E:\Downloads\" & Dir & "\" & i & ".jpg"
              Try
                My.Computer.Network.DownloadFile(targetFile, destFile, "", "", True, 10000, True, FileIO.UICancelOption.DoNothing)
            Catch ex As Exception
                tbStatus.Invoke(Sub()
                                    tbStatus.Text += vbNewLine & "ERROR: File: " & i & " ERR Number: " & Err.Number & ". Description: " & Err.Description & "File Name: " & targetFile
                                End Sub)
            End Try
          Next
      End Sub

And call it like:-

vbnet Code:
'
        Dim Dir As String = InputBox("Directory", "Dir")
         'Runs StartDownloads on a thread pool thread
        Threading.ThreadPool.QueueUserWorkItem(Sub() StartDownloads(Dir))

Now this is really a simple scenario. It doesn't account for progress or knowing when the downloads are finished but its the most straightforward way if you don't require any of the complexities of a more robust file download system.

----------


## green.pitch

Hello Niya, First of all Thanks for this delicious article. After reading your articles and reply here, I couldn't stop to ask.
I want to ask How can we pass multiple arguments on a thread.

Now As you have mentioned before that Thread.Start can accept only one parameter.. But why i am still asking because,

I have a Procedure which loads a .Txt file on a Listview.. in this function I pass .Txt file path and a Listview name.
Here I am not sure about how many times this procedure will be called. (It depends on number of .Txt files of a directory)

In other words, the procedure loads all the .Txt files of a directory on listviews.

Now my Query is, How to use ThreadPool to load all the .Txt files together. I mean instead of calling procedure one by one , how can i call this procedure to load the next .Txt file while the previous .Txt file is being loaded on the listview?

Here are the sample of codes i am talking about, Please have a look:


```
Public Sub LoadDB(ByVal bFile As String, ByVal LvName As ListView)
        Try
            Dim inputstream As New IO.StreamReader(bFile)
            Dim newstr(5) As String
            Dim ttt As String
                Do While inputstream.Peek <> -1
                    Application.DoEvents()
                    ttt = inputstream.ReadLine().Trim
                        newstr = Split(ttt, vbtab)
                        With LvName.Items.Add(newstr(0).ToUpper)
                            .SubItems.Add(newstr(1).ToUpper)
                            .SubItems.Add(newstr(2).ToUpper)
                            .SubItems.Add(newstr(3).ToUpper)
                            .SubItems.Add(newstr(4).ToUpper)
                        End With
                Loop
                inputstream.Close()
		Catch
		End Try
End Sub
```

And Normally I am calling it like :



```
For i = 1 to numberOftxtFiles
LoadDB(fileDirpath & i.ToString, LvPhH1)
LoadDB(fileDirpath & i.ToString, LvPhH2)
Next i
```

Even I am calling it like..


```
For i = 1 to numberOftxtFiles
Threading.ThreadPool.QueueUserWorkItem(Sub() LoadDB(fileDirpath & i.ToString, LvPhH1))
Threading.ThreadPool.QueueUserWorkItem(Sub() LoadDB(fileDirpath & i.ToString, LvPhH2))
Next i
```


But it's not working...

Thanks
Regards,  :Smilie:

----------


## green.pitch

Sorry for dual posting.... Above code was not working due to Cross thread Problem..

Now after 
CheckForIllegalCrossThreadCalls = False

it is working... Is it good to Disable CheckForIllegalCrossThreadCalls?

----------


## Niya

> Is it good to Disable CheckForIllegalCrossThreadCalls?


NO NO NO NO NO! Don't do that at all. You're begging for disasters in the future. I dedicated an entire paragraph towards explaining why you cannot call change control properties from a non-UI thread. I showed at least two ways to properly interact with controls from worker threads. One way by use the Invoke property of controls or by use of a SynchronizationContext object. I strongly suggest you go back and read those particulars again. You should *NEVER EVER* set CheckForIllegalCrossThreadCalls to False.

----------


## green.pitch

Ok thanks Niya, I tried to invoke a control on another project... But i am getting error. Please have a look to the following code.



```
  Private Sub LoadFrm(ByVal pIDD As String, ByVal pMsg As String)
        memFrmNum = memFrmNum + 1
        FrmObj(memFrmNum) = New Form2
        If FrmObj(memFrmNum).InvokeRequired Then
            FrmObj(memFrmNum).Invoke(New Action(Of String)(AddressOf LoadFrm), pIDD)
            FrmObj(memFrmNum).Invoke(New Action(Of String)(AddressOf LoadFrm), pMsg)
        Else
            FrmObj(memFrmNum).TextBox1.Text = pIDD
            FrmObj(memFrmNum).Label1.Text = pMsg
        End If
        FrmObj(memFrmNum).Show()
    End Sub
```

In above code I'm trying to load a form multiple times. Getting error on 'AddressOf LoadFrm'.

Please check the attachment.
ErrorOninvoke.zip

Regards,

----------


## Niya

> Ok thanks Niya, I tried to invoke a control on another project... But i am getting error. Please have a look to the following code.
> 
> 
> 
> ```
>   Private Sub LoadFrm(ByVal pIDD As String, ByVal pMsg As String)
>         memFrmNum = memFrmNum + 1
>         FrmObj(memFrmNum) = New Form2
>         If FrmObj(memFrmNum).InvokeRequired Then
> ...


The problem there is that you're are trying to invoke LoadFrm with Action(Of String) when you should be invoking with Action(Of String, String) because LoadFrm has two string parameters. However, you are targeting .Net 2.0 which doesn't seem to offer Action(Of T1, T2) so here is another way to correct it if you're using VS2010:-

vbnet Code:
'    Private Sub LoadFrm(ByVal pIDD As String, ByVal pMsg As String)        memFrmNum = memFrmNum + 1        If memFrmNum > 1000 Then memFrmNum = 1        FrmObj(memFrmNum) = New Form2        If FrmObj(memFrmNum).InvokeRequired Then            FrmObj(memFrmNum).Invoke(Sub() LoadFrm(pIDD, pMsg))        Else            FrmObj(memFrmNum).TextBox1.Text = pIDD            FrmObj(memFrmNum).Label1.Text = pMsg        End If        FrmObj(memFrmNum).Show()    End Sub

----------


## green.pitch

Oh ok thanks again Niya  :Smilie:  . I am very new in vb.net. Now the codes are not showing any error, but Form2 is still hanging after loading.. How can I solve this with Multi threading? Please check the attachment file of my last post. 

After clicking button on the form1, Open notepad.exe... and you will found Form2 will be hanging up.

How can we do it with Control properties on framework above 2.0?

If you can make any correction on it, please kindly do it.

Thanks again,
regards

----------


## Niya

What is that app supposed to do ?

----------


## green.pitch

> What is that app supposed to do ?


Its about a process gateway.. where if any new process will execute, app will prompt that new process name. .. It's for my personal use. And to clear my doubt, i thought it should be a good example to ask...  :Smilie: 

It's incomplete yet, Please suggest if you have any better idea to do its task.

Thank you Niya
Regards,

----------


## Niya

Well you have me at a disadvantage here. I haven't written any apps yet that deal with processes in complex way so I know little on this subject. I'm trying to understand how threading fits in here and what it is that you're trying to do with those Forms

----------


## green.pitch

> Well you have me at a disadvantage here. I haven't written any apps yet that deal with processes in complex way so I know little on this subject. I'm trying to understand how threading fits in here and what it is that you're trying to do with those Forms


Well Ok, I'm not asking to work on processes. What about the Multi threading on Form2 ? How to make free that form which is hanging.. It can be done by multi threading..  :Smilie:

----------


## Niya

> Well Ok, I'm not asking to work on processes. What about the Multi threading on Form2 ? How to make free that form which is hanging.. It can be done by multi threading..


What multi-threading on Form2 ? There is no code written inside Form2 at all.

----------


## OnErrorGoAway

Niya, after reading this thread and forcefeeding  :Confused:  myself on it, I registered--Just to thank you! :wave: 
I don't mean to slight any other posters, just that this topic is currently important to me.
I made the decision to finally ween off VB6 after writing an app to read 50,000 INT16 values from an industrial controller.
Using VB6/Winsocks, it is taking about 90 seconds.
With vb.net/multithreading/ (and whatever TCP client methodology I choose) I hope to trim down to less than 30 seconds.

----------


## Niya

If the task itself is parallelizable then you would definitely see an improvement in performance especially on systems with multi-core processors. I don't really know anything about reading from controllers but if you can read these integers by starting at an index then you can break the list up into several buckets and assign a thread to read each. However, if the controller itself can only be read at the hardware level as a serial device then that will be a bottleneck as there it wouldn't actually be reading in parallel. There would be no improvement.

I commend your effort to move away from VB6 and into VB.Net as its a much more powerful development tool by leaps and bounds but I cannot say for certain that it would help in this particular case.

----------


## OnErrorGoAway

I already have a vb6 app reading the data. The controller registers are indexed.
The parallel bucket reference is exactly my approach in the VB6 app , but sadly, VB6 isn't suited to multithreading.
I make multiple run-time instances of the WinSock control, issuing multiple queries on the controller, but then process the return data of each WinSock 'sequentially.'
That appears to be the bottleneck.
The controller access is via ethernet connection.  My initial concept was: multiple Operator Screens  can make simultaneous connections to the controller, 
so a pc app should be able to make multiple connections to the controller. Well, that concept has been proven - except for the VB6 limitations.

I have come here to read and learn First. Then ask for help later. So, thanks for the opportunity to 'read and learn!' Much appreciated.

----------


## Niya

> I already have a vb6 app reading the data. The controller registers are indexed.
> The parallel bucket reference is exactly my approach in the VB6 app , but sadly, VB6 isn't suited to multithreading.
> I make multiple run-time instances of the WinSock control, issuing multiple queries on the controller, but then process the return data of each WinSock 'sequentially.'
> That appears to be the bottleneck.
> The controller access is via ethernet connection.  My initial concept was: multiple Operator Screens  can make simultaneous connections to the controller, 
> so a pc app should be able to make multiple connections to the controller. Well, that concept has been proven - except for the VB6 limitations.


Well I don't think you will get a speed improvement by using multiple connections. There is only one physical connection so the data being transmitted over these multiple TCP/IP connections will be multiplexed into a single stream to be transmitted across the wire, so it would only appear to be working in parallel in code. The sum total transfer rate of say five TCP connections will be the same transfer rate as a single connection.

The only way to this could be truly parallel is if the controller itself allowed you to make multiple physical connections via multiple ethernet ports and cables. Then the device itself can truly work in parallel.




> I have come here to read and learn First. Then ask for help later. So, thanks for the opportunity to 'read and learn!' Much appreciated.


You're welcome  :Smilie:

----------


## OnErrorGoAway

Niya, 
In a preceding post you said that you were not detailing your ThreadExtensions  class. I got interested!
I have spent a couple days poring over those 14 lines, *F8*'ing through and also reading Nick's thread Here , among others.
I haven't figured out all of the class and _HOW_ it works, but I think that I have made progress in extending the parameter list.

I would appreciate if you could tell me if I am heading in the right direction, and if not, tell me so. 
The changes do work, but if I have made a dumb mistake, the IDE didn't tell me. 0 Errors, 0 Warnings, 0 Messages
[VB2010 Express]

My changes are highlighted in green, explanations are bold italic
I used the DateTime because I got bored with simple Integers


```
'Form1 code
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim DT As DateTime = #8/13/2002 12:14 PM# ' DateTime from MSDN example - just to notice a change when returned
        m_cn.CountAsync(600, 500, 50, DT) 'Changed Max to 600 and Added three new params (2 integer and one DateTime) -  I did change Min/Max of ProgressBar1
    End Sub

   Private Sub m_cn_CountChanged(ByVal sender As Object, ByVal e As CountChangedEventArgs) Handles m_cn.CountChanged
        ProgressBar1.Value = CStr(e.CurrentCount)
        Label2.Text = CStr(e.CurrentCount)
        Label3.Text = CStr(e.Mode) 'Show the new param as passed back
        Label4.Text = CStr(e.DT)  'Show the new param as passed back
        Label5.Text = CStr(e.Min) 'Show the new param as passed back

    End Sub
```



```
'Counter Class code
    Public Sub CountAsync(ByVal Max As Integer, ByVal Min As Integer, ByVal Mode As Integer, ByVal DT As DateTime) 
        '>>------------------------------------ Change New Func Signature and Count Signature
        ThreadExtensions.QueueUserWorkItem(New Func(Of Integer, Integer, Integer, DateTime, String)(AddressOf Count), Max, Min, Mode, DT) 
    End Sub

'Add new variables declarations to the Count signature
   Public Function Count(ByVal Max As Integer, ByVal Min As Integer, ByVal Mode As Integer, ByVal DT As DateTime) As String
        Dim startTime As DateTime = DateTime.Now
        Dim e As CountChangedEventArgs
        Dim msg As String

        For i = 1 To Max
            e = New CountChangedEventArgs(i, Max, Min, Mode, DT) 'Add return variables here

            If context Is Nothing Then
                OnCountChanged(e)
            Else
                ThreadExtensions.ScSend(context, New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), e)
            End If

            Threading.Thread.Sleep(200)
        Next

        msg = "Count took : " + (DateTime.Now - startTime).ToString

        If context Is Nothing Then
            OnCountCompleted(New CountCompletedEventArgs(msg))
        Else
            ThreadExtensions.ScSend(context, New Action(Of CountCompletedEventArgs)(AddressOf OnCountCompleted), New CountCompletedEventArgs(msg))
        End If

        Return msg
    End Function
```



```
'CounterChangedEventArgs Class code

    Private _Max As Integer
    Private _Min As Integer  ' Support first ADDED variable
    Private _Mode As Integer ' Support second ADDED variable
    Private _DT As DateTime ' Support third ADDED variable

   Public Sub New(ByVal cc As Integer, ByVal max As Integer, ByVal min As Integer, ByVal Mode As Integer, ByVal DT As DateTime)
        _CurrentCount = cc
        _Max = max
        _Min = min 'Get the new value to return to UI
        _Mode = Mode 'Get the new value to return to UI
        _DT = DateTime.Now  'Get the new value to return to UI
    End Sub

'Finally, add support for the public properties

   Public ReadOnly Property Min() As Integer
        Get
            Return _Min
        End Get
    End Property
    Public ReadOnly Property Mode() As Integer
        Get
            Return _Mode
        End Get
    End Property
    Public ReadOnly Property DT() As DateTime
        Get
            Return _DT
        End Get
    End Property

```

Thank you for your time and effort!

----------


## Niya

> I would appreciate if you could tell me if I am heading in the right direction, and if not, tell me so. 
> The changes do work, but if I have made a dumb mistake, the IDE didn't tell me. 0 Errors, 0 Warnings, 0 Messages
> [VB2010 Express]


You did everything 100% correctly. If this were a test, you'd get an A++  :Big Grin: 




> In a preceding post you said that you were not detailing your ThreadExtensions class. I got interested!
> I have spent a couple days poring over those 14 lines, F8'ing through and also reading Nick's thread Here , among others.


Note that if you're using VS2010 that the ThreadExtensions class is not necessary because the VB2010 compiler gives you a Sub keyword for lambdas that don't return a value so you can use QueueUserWorkItem of the ThreadPool class directly and specify a Sub lambda to call your functions. Its far more terse that using ThreadExtensions.

Eg: This:-

vbnet Code:
ThreadExtensions.QueueUserWorkItem(New Func(Of Integer, Integer, Integer, DateTime, String)(AddressOf Count), Max, Min, Mode, DT)

Can become:-

vbnet Code:
ThreadPool.QueueUserWorkItem(Sub() Count(Max, Min, Mode, DT))

ThreadExtensions is necessary if you're using VS2008 which doesn't have a Sub keyword.

----------


## OnErrorGoAway

> You did everything 100% correctly. If this were a test, you'd get an A++


Thank you. You are too kind.




> the VB2010 compiler gives you a Sub keyword for lambdas that don't return a value so you can use QueueUserWorkItem of the ThreadPool class directly and specify a Sub lambda to call your functions.


Works as specified. Thank you, again.

----------


## OnErrorGoAway

Niya,
I have Button1.Enabled = False in Button1_Click and then Button1.Enabled = True  in m_cn_CountCompleted(..)
I read that threadpool threads do NOT re-init any data from the last usage of that thread. Here
Now, since I am interlocking Button1 click, the same thread must be used the next time that I click  Button1.

My reason/evidence for this is that the Count function does NOT restart at my new min value -- it is at max immediately!
Before interlocking the button, 'new' threads started at min.
In the original function, *i* is not declared, so I declared Dim i As Integer = 0, and the count starts at min again.

Does this sound reasonable?

source MSDN



> When the thread pool reuses a thread, it does not clear the data in thread local storage or in fields that are marked with the ThreadStaticAttribute attribute. 
> Therefore, when a method examines thread local storage or fields that are marked with the ThreadStaticAttribute attribute, the values it finds might be left over from an earlier use of the thread pool thread.

----------


## Niya

i is not using thread local storage. It is stored on the stack which means the values no longer exist when the function exits. Thread local storage has to explicitly be used. It is never implicit. So that observation has nothing to do with thread local storage. Please explain what you mean by "interlocking" the button.

----------


## OnErrorGoAway

Interlocking may have been a poor choice of terminology for .Net.
I meant that I disable the the button (Button1) when clicking it and then re-enabling it in m_cn_CountCompleted(..) sub.

I was trying to provide a cause for what I observed. With your assessment I think that I found my problem. -- it was NOT a thread local storage issue...
I was trying to 'cancel' (or in this case HURRY-UP) the thread by passing a bool value to it.
I never reset the bool value in the code in Form1.

I do not know if it is correct to pass a 'Cancel' bool to the running thread, but what I have done is:
overloaded the Count function with


```
    Public Overloads Sub Count(ByVal Cancel As Boolean)
        CancelRequest = Cancel
    End Sub
```

and in the Count function, check for CancelRequest, to let the thread handle the Cancel request. ( I feel that it is better than attempting to abort a thread)


```
        
Public Overloads Function Count(ByVal Max As Integer, ByVal Min As Integer, ByVal Mode As Integer, ByVal DT As DateTime) As String 
.
.
.
       For i = Min To Max
            If Not CancelRequest Then
                e = New CountChangedEventArgs(i, Max, Min, Mode, DT) 

                If context Is Nothing Then
                    OnCountChanged(e)
                Else
                    ThreadExtensions.ScSend(context, New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), e)
                End If

                Threading.Thread.Sleep(50)
            Else
                i = Max
            End If
        Next
.
.
.
End Function
```

If a better/correct way exists, I haven't read about it or found it yet. I will keep plodding on.
Thank you for your valued input!

----------


## Niya

> ( I feel that it is better than attempting to abort a thread)....
> If a better/correct way exists, I haven't read about it or found it yet. I will keep plodding on.
> Thank you for your valued input!


You have a knack for this. Yes what you're doing is the correct way. You use a cancel field and let the thread cancel itself. You never ever want to abort a running thread. Only the thread itself knows about its internal state so it should be responsible to stopping itself. From the outside you cannot know where the thread is currently at so aborting from the outside can cause some nasty side effects. 

For example, imagine a thread that opens files in a list one by one. You want when you stop the thread, that it closes the current file it has open before aborting. Its easy to do that from inside the thread, if a cancel variable was set you close and exit whatever loop is iterating the list. But if you try to abort the thread from the outside, you could have called it smack in the middle of reading a file and it would just stop abruptly, leaving the file opened and possibly locked.

----------


## OnErrorGoAway

Niya,
Am I missing something?
You mentioned earlier that 



> ThreadExtensions class is not necessary because the VB2010 compiler gives you a Sub keyword for lambdas


Does this hold true for your ThreadExtensions.ScSend(..., or was that statement directed at starting a thread?

----------


## Niya

Yes, it applies to ScSend as well as it also takes a delegate argument.

----------


## OnErrorGoAway

Thank you. Another puzzle.  :big yellow: 

RE: my project (post #86)
I am StopWatching it at 10.9 seconds in IDE and 10.2 seconds in .EXE.
I have two 'iterations' of 25 threads, each thread making a connection and reading 10 blocks of data, shutting down and closing the connection, then reporting that data back to UI.
Each thread updates its UI ProgressBar  after each of the 10 reads and then at completion dumps its data to a TextBox.
This is a learning demo so I am not ready to ask for any help. I know that my project has kludges, but they will be removed as my understanding increases. :Confused: 
I have merged multiple examples from this forum and other sources such as MSDN. Thanks to all.
Now, I must understand how it does what it does.
[EDIT:Replace string functions with stringbuilder]
I am StopWatching it at 9.7 seconds in IDE and 9.6 seconds in .EXE.

Edit: just received books
-Programming VB.Net (Cornell & Morrison)
-VB 2010 Prog Ref (Stephens)
So I may be absent for a while  :Thumb:

----------


## Niya

Ok well, good luck to you my friend. I'll always be around if you have any questions.  :Smilie:

----------


## OnErrorGoAway

RE: ThreadExtensions [Niya VB2008] -vs- SendOrPostCallback [VB2010]
I think that I may be on to something! I have been *F8*'ing some more.
If I have done something really wrong, please do not hesitate to correct me!
Replace:


```
                  
 ThreadExtensions.ScSend(context, New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), e)
```

with this:


```
 context.Send(New SendOrPostCallback(Sub(state As Object) RaiseEvent CountChanged(Me, e)), Nothing)
```

CountChanged worked.

Then replace this:


```
 ThreadExtensions.ScSend(context, New Action(Of CountCompletedEventArgs)(AddressOf OnCountCompleted), New CountCompletedEventArgs(msg))
```

with this:


```
       
 Dim em As CountCompletedEventArgs
.
.
.
 em = New CountCompletedEventArgs(msg)
.
.
.
 context.Send(New SendOrPostCallback(Sub(state As Object) RaiseEvent CountCompleted(Me, em)), Nothing)
```

CountComplete worked.


Notes:
VB default project settings
Option Explicit ON
Option Strict ON
Option Compare BINARY
Option Infer ON
--If I had .Net Reflector, I would need this chair removed surgically!--

----------


## Niya

Yes, those are correct but a little too verbose for my tastes. You could just do this:-

vbnet Code:
context.Send(Sub() RaiseEvent CountChanged(Me, e)), Nothing)

----------


## make me rain

Niya it will be great to see if you start some thread on LINQ (vb.net) please

----------


## Niya

> Niya it will be great to see if you start some thread on LINQ (vb.net) please


Aite  :Wink:

----------


## KGComputers

Great post on Multithreading!

Have you by any chance created a sample code in C#?

If not, I'll just stick with the VB.NET example and play around 
with it.

KG

----------


## Niya

> Have you by any chance created a sample code in C#?


No I haven't. It would be exactly the same in C#. Only the syntax would differ. As a matter of fact, you should have little to no problems using an online converter to convert the samples to C#.

----------


## KGComputers

Great!

Thanks..  :Smilie:

----------


## sorgu

Thanks for source code

----------


## Niya

You're welcomed.

----------


## Mogge

Hi Niya

Sitting here reading your very well described article about Multi-Threading - great reading!! Enjoyed it very much.

I'm working on a Windows service that amoung other things will scan a number of servers on the Network and due to the length of a server scan I'm thinking of building a Multi-Threading code to handle this. That way I am able to start let's say 50 scans at the same time. There could be a lot more servers - might be up 4.000....
Now it is just the question on how.

My Sub called *ScanServer(ServerName as string)* will need to be called but I want to be able to set a max on how many scans that can run at the same time - 50 is a starting point but not a static number.

I have the server names in a list

Private ServerList As New List(Of ServerClass)

ServerClass defined as:

Public Class ServerClass

    Public ServerName As String
    Public IPAddress As String

    Sub ServerClass()
        ServerName = String.Empty
        IPAddress = String.Empty
    End Sub

End Class


How do I put together a piece of code that can start the scans (up to X number at a time) and keep them filling the queue until the last server is scanned?
The Sub (ScanServer) will not return any data - the scan will be written into a XML file on the disk so I have no demand for keeping track of the thread while running.


Thanks in advance!!


Best Regards
/Mogge

----------


## Niya

I'm curious, why do you have this:-

vbnet Code:
ScanServer(ServerName as string)
instead of:-

vbnet Code:
ScanServer(ServerName as ServerClass)

----------


## Mogge

Sure - I'm currently in the building phase and all things are not settle yet.

I find your suggestion very good.

/Mogge

----------


## Niya

Booo!

----------


## demanaz

sorry if this has already been answered, lots of activity  :Smilie: ....

Why do you use AddressOf instead of Sub()? Sub() allows you specify multiple parameters. Does AddressOf offer better performance or error handling?

----------


## Niya

> sorry if this has already been answered, lots of activity ....
> 
> Why do you use AddressOf instead of Sub()? Sub() allows you specify multiple parameters. Does AddressOf offer better performance or error handling?


Could specify exactly where you're talking about? Been a while since I looked over the code. I can't recall off hand.

----------


## pthegr8

Hi Niya,
thank you for this thread. I'm relatively new to programming and VB.net. I use VS'13 and SQL server Express.
I'm in the middle of programming an app that does the following:
through a 3rd party ActiveX API I read in records to a SQL table at high rate; several million records in 8hours a day.
While the streaming of the records occurs, I need to go over the records, do some calculations and apply filters, and represent the results in realtime. (filters it down to around a 100 records/day)
I guess you see already where I'm going with this;
Currently I do the calculations/filters on the fly when records are streaming in; this causes the streaming to delay and I loose the connection, So I need to multi-thread the two tasks.

the streaming into SQL table is done as follows:
On Form1 :



```
    Private Sub SubscrBTN_Click(sender As Object, e As EventArgs) Handles SubscrBTN.Click
        AxTDAAPIComm1.Subscribe(StreamOL, tdaactx.TxTDASubTypes.TDAPI_SUB_L1)
    End Sub
    Private Sub AxTDAAPIComm1_OnL1Quote(sender As Object, e As Axtdaactx.ITDAAPICommEvents_OnL1QuoteEvent) Handles AxTDAAPIComm1.OnL1Quote
        SQL.AddStream(e.quote.Symbol, e.quote.Bid, e.quote.Ask, e.quote.Last, e.quote.PrevClose, e.quote.Volume, e.quote.TradeTime, e.quote.QuoteTime, e.quote.TradeDate, e.quote.QuoteDate, e.quote.Volatility, e.quote.OpenInterest, e.quote.UnderlyingSymbol, e.quote.CallPut, e.quote.LastSize, e.quote.MH_LastSize, e.quote.MH_IsQuote, e.quote.MH_IsTrade)
    End Sub
End Class
```

clicking on the button, invokes the AxTDAAPIComm1_OnL1Quote sub, which streams back records.
Then in my SQL Class I send it off to my SQL table:



```
    Public Sub AddStream(Symbol As String, Bid As Single, Ask As Single, Last As Single, PrevClose As Single, Volume As Integer, TradeTime As Integer, QuoteTime As Integer, TradeDate As Integer, Quotedate As Integer, Volatility As Single, OpenInterest As Integer, UnderlyingSymbol As String, CallPut As String, LastSize As Integer, MH_LastSize As Integer, MH_IsQuote As Boolean, MH_IsTrade As Boolean)
        Try
            Dim TradeAmount As Single = 0
            Dim Trade As String = ""


            TradeAmount = LastSize * Last * 100
            Select Case Last
                Case Is = Ask
                    Trade = "Ask"
                Case Is > Ask
                    Trade = "Above Ask"
                Case Is = Bid
                    Trade = "Bid"
                Case Is < Bid
                    Trade = "Below Bid"
                Case Else
                    Trade = "Mid"
            End Select


            Dim strStream As String = "INSERT INTO OptionStream (Symbol,Bid,Ask,Last,PrevClose,Volume,TradeTime,QuoteTime,TradeDate,QuoteDate,Volatility,OpenInterest,UnderlyingSymbol,CallPut,TradeAmount,Trade,LastSize,MH_LastSize,MH_IsQuote,MH_IsTrade) " & _
                                      "VALUES (" & _
                                      "'" & Symbol & "'," & _
                                      "'" & Bid & "'," & _
                                      "'" & Ask & "'," & _
                                      "'" & Last & "'," & _
                                      "'" & PrevClose & "'," & _
                                      "'" & Volume & "'," & _
                                      "'" & TradeTime & "'," & _
                                      "'" & QuoteTime & "'," & _
                                      "'" & TradeDate & "'," & _
                                      "'" & Quotedate & "'," & _
                                      "'" & Volatility & "'," & _
                                      "'" & OpenInterest & "'," & _
                                      "'" & UnderlyingSymbol & "'," & _
                                      "'" & CallPut & "'," & _
                                      "'" & TradeAmount & "'," & _
                                      "'" & Trade & "'," & _
                                      "'" & LastSize & "'," & _
                                      "'" & MH_LastSize & "'," & _
                                      "'" & MH_IsQuote & "'," & _
                                      "'" & MH_IsTrade & "') "


            SQLCon.Open()
            SQLCmd = New SqlCommand(strStream, SQLCon)
            SQLCmd.ExecuteNonQuery()
            SQLCon.Close()


        Catch ex As Exception
            MsgBox(ex.Message)
        End Try


    End Sub
```

perfect works great!

On my Form I have created a text box, which I use to enter a SQL query statement, which I capture as follows:



```
    Private Sub cmdQuery_Click(sender As Object, e As EventArgs) Handles cmdQuery.Click
        If txtQuery.Text <> "" Then
            If SQL.HasConnection = True Then
                SQL.RunQueryWL(txtQuery.Text)
                If SQL.SQLDatasetWL.Tables.Count > 0 Then
                    DGVData.DataSource = SQL.SQLDatasetWL.Tables(0)
                End If
            End If
        End If
    End Sub
```

As you can see, it now goes of to the SQL class and runs the Query:



```
    Public Function HasConnection() As Boolean
        Try
            SQLCon.Open()
            SQLCon.Close()
            Return True
        Catch ex As Exception
            MsgBox(ex.Message)
            Return False
        End Try
    End Function
    Public Sub RunQueryWL(Query As String)
        Try
            SQLCon.Open()
            SQLCmd = New SqlCommand(Query, SQLCon)


            SQLDA = New SqlDataAdapter(SQLCmd)
            SQLDatasetWL = New DataSet
            SQLDA.Fill(SQLDatasetWL)
            SQLCon.Close()
        Catch ex As Exception
            MsgBox(ex.Message)
            If SQLCon.State = ConnectionState.Open Then
                SQLCon.Close()
            End If
        End Try
    End Sub
```

and the result is presented in a datagrid view on my form.
As you can imagine, querying against a couple million records takes a few seconds, therefore I need to move the whole query routines onto a different thread, so that the streaming won't get interrupted.
Any ideas on how I can do this?

I'm still trying to grasp the whole concept, so any detailed info you can give me will be greatly appreciated.

----------


## StatShacker

Niya, 
    At this point I don't suppose you ~need~ to hear again what an outstanding job you've done here but I think you should here it!!! And like several others, your posts and in particular your responses to the replies of others inspired me to register here just to tell you how much I appreciate how cogent your instructions are, how patient you are in your responses to nuubs (myself included hopefully), how generous you are of your time to continue supporting this thread now for over almost two and a half years and (he bows his head in embarrassment) to ask a few questions of my own.  
     Notwithstanding my questions, my inspiration to register came from my need to tell you that *you are truly the "Angel of Code," for this is, by far, the best thread on multi-threading (sorry for the pun) that I've found and I am certain not to find one better*.  What has made this thread even better are some of the queries to it and your thoughtful, helpful and instructive responses to them.  I hope that (even as a nuub) my questions can make a contribution in this realm.

Question 1) Please confirm. (my situation) If you have a third party component instantiated in the main thread; when you handle a callback from that component, the callback is directly run in the main UI thread, if the callback delegate and method are in the code for the main form, yes?  I am pretty sure the answer is 'Yes,' but I'm not 100% sure that the code in the component (clearly a separate thread) extend itself into the callback method... 
Question 2) Please confirm.  Some of your responses to queries were (understandably) VB.Net Framework version dependent .  With the final version of your post (i.e., using the "QueueUserWorkItem" of ThreadPool, which works under Framework 3.5, my target), is it necessary to "EndInvoke" this thread?  Again I'm pretty sure, based on reading descriptions written elsewhere about ThreadPool, but ask so I can sleep at night with no lingering doubts...  
Question 3) I have an app that receives a callback from an embedded component.  The callback is fed into the main UI thread (assuming your answer to question 1 is 'Yes').  The issue is that the callback can occur anywhere from 0 to 100 times (or more) per second and each time requires the app to do a number of things including updating a database and the UI.  This is an obvious opportunity to use multi-threading (otherwise, the responsiveness of the UI would be compromised).  My assumption and my question is that instantiating a static thread for this callback to use is the way to go (yes?) and.... how would I best manage it?
Question 4) Finally, is there a pattern that is similar to the one in your posts, but which uses Begin/End Invoke and why might it better or worse than "QueueUserWorkItem" in your opinion? (this seems ~similar~ to the ConnectionThread discussion you had with psoftware, but not enough so to make it clear to me how to proceed).

Thanks Ever So Much :-)

----------


## passel

While waiting for Niya, I'll give my opinion on some aspects of Questions 1 and 3.
I wouldn't assume the callback ran on the main thread. The opposite is usually the problem that people run into.
For instance, using a serialport object and trying to update a GUI element in the DataArrival event.
The component is running in another thread, and posts DataArrival events using yet another thread, so that it doesn't hang itself up from reading the serialport.
When the user in the DataArrival event tries to update a GUI element, they get a crossthread access violaton.
My assumption would be that the "callback" is not run on the GUI thread, and that can be tested by seeing if Invoking is necessary.

----------


## StatShacker

Sometimes all that a young child needs (though I am most decidedly not young!), to hear is "No" and they "get it."  passel, your reply was that for me, thanks!  Though its been quite some time since, earlier I got intermittent crossthread access violation along with the UI slowdown as the callbacks were being processed.  These two things brought me to the conclusion that I must add a separate thread generated within the callback to handle it and avoid both problems.  I did so and "solved" the problem(s), ostensibly.  This only generated a problem that hasn't exposed itself until now, a memory leak (a poor implementation of the BeginInvoke/EndInvoke pair).  The memory leak has caused me to reconsider all and which has allowed me to find Niya's wonderful discussion here.
I feel I'm getting closer to a well constructed fix, if only cognitively at this point, with all the help I've found in this thread.
But curiously, to the point of your reply, while the callback did generate crossthread violations, it also caused the UI to slow to a crawl.  How is this possible, i.e., a callback, with clear "ties" to a thread separate from the main UI thread (your point), also slow the main UI thread?  It would seem that it would be either a crossthread violation or a UI slow down, but no both, yes?  Is this even possible? Or, is the slow down the result of some other side effect?  Note: the callbacks UI updates were not a continuous flow of updates rather, updates to text boxes and graphical objects based on summary results of the callback.
PS thanks for your reply passel!

----------


## pthegr8

so I'm trying the following:



```
   Private Sub cmdQuery_Click(sender As Object, e As EventArgs) Handles cmdQuery.Click
        sw.Restart()
        sw.Start()
        If txtQuery.Text <> "" Then
            If SQL.HasConnection = True Then
                Threading.ThreadPool.QueueUserWorkItem(AddressOf DoQry)
            End If
            ' End If
        End If
    End Sub
    Private Sub DoQry()
        SQL.RunQuery(txtQuery.Text)
        UpdateGrid()
    End Sub
    Private Sub UpdateGrid()
        If DGVData.InvokeRequired Then
            DGVData.Invoke(New action(AddressOf UpdateGrid))
        Else
            DGVData.DataSource = SQL.SQLDataset.Tables(0)
            ETlbl.Text = sw.ElapsedMilliseconds
        End If
    End Sub
```


While records are streaming into my SQL Table, at >200 records/second, I invoke a SQL query against it : a simple "select * from Optionstream" , which takes about 7 seconds.
However now I get an error: " The connection was not closed, The connection's current state is open".
which is the Exception error from the Try-Catch in my Addstream sub in the SQL Class. see previous post.

Before I added the multi-threading this was not the case. 
What am I doing wrong?

----------


## walterwjl

Hi, just wanted to ask something, if we start an app, and in the app start a thread, and then we close the app, will the thread also close or will it continue until it's done with what it had to do?

----------


## passel

It depends on if the thread is a Background thread (it will end when the main thread, aka the GUI thread in a winforms application ends) or not.
If it is not a background thread, it will continue to run until it finishes.
<edit> Just realized that this in the CodeBank forum. You should post questions like these in a new thread, rather than in a CodeBank thread. </edit>

----------


## Irek Janek

It will continue, you can test this by (while debug mode) creating and starting a new thread with an infinite loop and closing the app. Now if you look at your controls inf Visual Studio you will see that the START button is disabled and the STOP button is enabled even though your app should be done.

----------


## Irek Janek

This thread is ancient but it still seams to get some interest. If you guys are interested I created a jump-start Video Tutorial on Multi-Threading. It's on YouTube http://www.youtube.com/playlist?list...3Sfvzlsha4Jdnk

----------


## Niya

> Hi, just wanted to ask something, if we start an app, and in the app start a thread, and then we close the app, will the thread also close or will it continue until it's done with what it had to do?





> It will continue, you can test this by (while debug mode) creating and starting a new thread with an infinite loop and closing the app. Now if you look at your controls inf Visual Studio you will see that the START button is disabled and the STOP button is enabled even though your app should be done.


As passel said, it depends on if the thread in question is a background thread. I explained in the tutorial that an application stops only when all foreground threads are stopped. When all foreground threads are stopped then all background threads will also be terminated and no infinite loop will prevent this.

----------


## Niya

> Niya, 
>     At this point I don't suppose you ~need~ to hear again what an outstanding job you've done here but I think you should here it!!! And like several others, your posts and in particular your responses to the replies of others inspired me to register here just to tell you how much I appreciate how cogent your instructions are, how patient you are in your responses to nuubs (myself included hopefully), how generous you are of your time to continue supporting this thread now for over almost two and a half years and (he bows his head in embarrassment) to ask a few questions of my own.  
>      Notwithstanding my questions, my inspiration to register came from my need to tell you that *you are truly the "Angel of Code," for this is, by far, the best thread on multi-threading (sorry for the pun) that I've found and I am certain not to find one better*.  What has made this thread even better are some of the queries to it and your thoughtful, helpful and instructive responses to them.  I hope that (even as a nuub) my questions can make a contribution in this realm.


Nice to hear this has been helpful.  :Smilie: 




> Question 1) Please confirm. (my situation) If you have a third party component instantiated in the main thread; when you handle a callback from that component, the callback is directly run in the main UI thread, if the callback delegate and method are in the code for the main form, yes?  I am pretty sure the answer is 'Yes,' but I'm not 100% sure that the code in the component (clearly a separate thread) extend itself into the callback method...


I think you may be holding onto a few misconceptions. Firstly, objects aren't really thread specific in the strictest technical terms. While some classes might goad you into paying attention to the thread they were created on, know that there is nothing inherent in the operation of the .Net Framework that says that an object belongs to a particular thread. This is all the work of the person who wrote the class. They can choose to have that class execute its methods on that thread or to have them executed on only the UI thread regardless of where it was created.

*Executing methods are thread specific*, not the classes that define them. That being said, you can never make assumptions about what thread a callback will be executed on. The only way to be certain is to consult the documentation for the component. A properly documented component will inform you how their callbacks are executed. However, there are common patterns surrounding callbacks that can help you make a well informed guess. One such pattern is the asynchronous pattern which you might have seen on classes like the Socket class. The Socket class has several methods which have asynchronous variants. In those cases, callbacks are employed to signal either the failure or success of an operation. These callbacks are usually executed on a worker thread. If you see a pattern like that, you can make a well informed guess. But its still not a guarantee.





> Question 2) Please confirm.  Some of your responses to queries were (understandably) VB.Net Framework version dependent .  With the final version of your post (i.e., using the "QueueUserWorkItem" of ThreadPool, which works under Framework 3.5, my target), is it necessary to "EndInvoke" this thread?  Again I'm pretty sure, based on reading descriptions written elsewhere about ThreadPool, but ask so I can sleep at night with no lingering doubts...


No, you don't need to call and type of 'EndInvoke' method for QueueUserWorkItem. EndInvoke is usually employed with the asynchronous pattern I mentioned above.

----------


## machine

How exchange messages in string threads? Like " ok finish functions" or " not yet wait..."

----------


## Niya

Well it depends. If you want some thread to indicate when its finished doing something, you can have the object raise an event signalling that its finished. If you want different threads within the same object to communicate, you can use some kind of polling. You will have to use a class scoped variable and poll against that.

----------


## machine

receiveThrd = New Threading.Thread(AddressOf recv)
procprotoThrd = New Threading.Thread(AddressOf Protocol)

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        send data
	pooling thread protocol ' wait device response
	send string tell me data packet arrived
	yes finish! 
	data expectate = data received
	process...

    End Sub

Private Sub protocol()


    End Sub

Private Sub recv()

  End Sub

sorry incomplete code, but searching and not found how exchange information in threads. Thanks for repply.

----------


## topshot

Your code looks fairly similar to dbasnett's so check out his Protocol sub in this post

----------


## Niya

> Your code looks fairly similar to dbasnett's so check out his Protocol sub in this post


Yea, that seems to be precisely it.

----------


## machine

Yes, it works fine but the thread only update Label and process datareceived. I want  do in realtime, send command and pooling thread Protocol() with data arrived. I'm using this post for understanding how threads interact.

I try this sample: https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx

thanks!

----------


## Niya

I don't understand what you're asking.

----------


## ThePPV

Hi!

First Post Here! Self-taught vb.net programmer here!

Thanks for this (old!) topic which is still very relevant!

I do have a problem adapting your example to my situation though.

I have made this ticket monitoring app that makes requests to a DB and puts the info into Datagridview object. Now I want to put the DB subroutines through another process, and your code achieives this. Where I have a problem is in updating the DGV... 

The sub that is threaded make these call to the thread that will invoke:


```
row = New String() {OdbcDr.GetValue(0).ToString(), OdbcDr.GetValue(9).ToString(), OdbcDr.GetValue(10).ToString(), OdbcDr.GetValue(1).ToString(), OdbcDr.GetValue(11).ToString(), OdbcDr.GetValue(2).ToString(), OdbcDr.GetValue(7).ToString(), OdbcDr.GetValue(4).ToString(), ONS & strHour}
ThreadUpdateDGV(row)
```

As you can see I pass a string array into an rows.add to my DGV...

And it works because when I debug I can see my values are passed correctly

here is part of the sub that use the Invoke:



```
   Protected Sub ThreadUpdateDGV(ByVal myrow As String())
                If dgvTickets.InvokeRequired Then
                    dgvTickets.Rows.Clear()
                    dgvTickets.Invoke(New Action(Of String())(AddressOf ThreadUpdateDGV), myrow)
          Else
                    dgvTickets.Rows.Add(myrow)
                End If
```

I do think I incorrectly call the Invoke for the DVG but, for the life of me, I come up empty. Can you tell me what I do wrong?

----------


## Niya

You are clearing the DGV every time you check InvokeRequired. Remove that line:-

vbnet Code:
dgvTickets.Rows.Clear()

----------


## ThePPV

> You are clearing the DGV every time you check InvokeRequired. Remove that line:-
> 
> vbnet Code:
> dgvTickets.Rows.Clear()


I did (got it when reviewing the code I sent, but I still have the same problem..

----------


## Niya

Did you check the value of that String array you're passing in ?

----------


## ThePPV

I get a "TargetParameterCountException was hunandled" error...

----------


## ThePPV

Yeah. The values are passed correctly, I see that they are what I am waiting for. It seem the Invoke does not like working with arrays...

----------


## ThePPV

WHile using a break point I see this in the properties of the DGV I am invoking:

AccessibilityObject = {System.InvalidOperationException: Opération inter-threads non valide*: le contrôle 'dgvTickets' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé.     à System.Windows.Forms.Control.get_Handle()     à System.Windows.Fo...

Translation: the control is subject to access from another thread than the one it was created on...

----------


## Niya

Your problem might have something to do with how you are adding those rows. The threading code is correct so I can only assume the problem lies elsewhere. For one thing the documentation for the DGV doesn't indicate that there is an Add overload that takes a String array.

----------


## BrandonL

Niya,

Thanks!  As many have said, this was a great explanation of threading, and your continued support is really impressive!  Thanks for giving back!

Personally, I am having a little trouble relating your example to my situation.  I have successfully connected to a serial port via the serial port class which of course has its own events.  I then use the incoming data to update a textbox.  There are plenty of examples of how to do this elsewhere but they are over simplified and simple use Textbox.Invoke to get back to the UI thread from the serial port.  Those work, but since the serial port is constantly receiving data, the UI thread never regains control.  Plus, eventually, I want to use the incoming data to update multiple custom controls rather than simply updating just one textbox.  Previously, I initialized mySerialPort in the main UI thread, but now that I read through your examples, I'm thinking I should open the serial port in a separate class, but then I circle back and say, "well the serial port is already a separate class isn't it?"

Thanks in advance!

----------


## Niya

Well I've never written anything that uses serial ports but I imagine that whatever class you're using to receive data has asynchronous methods. You can simply use those methods if you don't want to wrap the serial port code inside another class. However, if you're going to use synchronous methods then it would ultimately cause less headaches if you wrap your serial port communication inside a class and use worker threads to run the methods asynchronously.

----------


## passel

I assume you're processing data in the DataReceived event, which executes in a thread kicked off by the SerialPort object.
If your data is coming fast enough that your GUI has a hard time doing the things it needs because of constant invoking, as Niya says you can try BeginInvoke instead which is asynchronous.
I'm a little cautious with BeginInvoke. If the data is slow enough that I know I won't be overlapping BeginInvoke calls, then using BeginInvoke to avoid holding the receiving thread any longer than necessary I like. But if the data is coming fast, and I'm calling BeginInvoke repeatedly, so that calls can overlap with previous asynchronous invocations not completed, can lead to issues, depending on if you're using reference types, etc.

My preference is to push the received data in the serial receiver onto a concurrent queue, and have a "GUI Timer", that is responsible in the GUI thread of periodically checking the queue and processing the data and updating the GUI elements. Usually I have the GUI timer operating at 10hz to update the GUI, while the various Serial ports, and Ethernet ports communicating with various machines at various rates at the same time.
That keeps the GUI thread responsive, and reflecting data the user needs, and keeps from tying up the various communication interfaces that are receiving data.

----------


## BrandonL

I guess the problem I'm having is the fundamental difference between the example and my goal.  Your example uses a for loop iterating I to trigger the CountChanged Event within the Function Count.  I have no such function.  The serial port object is created and a connection established, then the DataReceived event fires on its own thread.  I have been able to intentionally open the serial port on a new thread, but since I'm not in control of its events, I can't (or don't know how to) reacquire the thread to the UI.
Mind you I can of course, just use invoke on all the UI objects individually, but that's what we are trying to avoid here isn't it?

----------


## BrandonL

@passel




> I assume you're processing data in the DataReceived event, which executes in a thread kicked off by the SerialPort object.


That's exactly right.

Yep you lost me.   :Blush:   You're suggesting to store the incoming data in a buffer, and only update the GUI periodically?

----------


## passel

> ...  Your example uses a for loop iterating I to trigger the CountChanged Event within the Function Count.  I have no such function.  ...


Which example are you referring to? I have used different flavors of processing at different times, so I'm not sure what we're referencing. Also, if this is a particular discussion of implementation, it probably should be continue in another (new) thread, not this one.

----------


## BrandonL

Sorry, I should have said THE example, referring to Niya's original examples.

----------


## passel

I would say, start a new thread, where this can be discussed, and you can show examples etc. without diluting the purpose of the CodeBank thread, which is to provide a working example of code.

----------

