This Question has 2 parts. I am new to multithreading and so I want to firstly check if my logic is correct and then I want to find out how to handel erros in multithreading.
Q1: I have an application that calls SQL database obtaining information from 2 datatables, this info is then combined in a final display. Without multithreading, I call each SQL select to populate a dataset one after the other. With multithreading I call the more complex SQL first as a separate thread and then the less complex SQL call in the main thread second. I am trying to cut down the load time of both by doing them concurently.
(I realise that strictly I should do both as backround tasks to free up the UI, for me its small steps first)
Anyway the code looks little like this
Dim ThreadLoad_Longer_Data As Thread
ThreadLoad_Longer_Data = New Thread(AddressOf Me.Fill_LongerSQL)
ThreadLoad_Longer_Data.IsBackground = True
TThreadLoad_Longer_Data.Start()
'Execute some code here for the second SQL call in main thread
'Then stop the main prosess to wait for the finish of the of the background
ThreadLoad_Longer_Data.join
Im assuming that the .Join statment will infact stop the main thread and will wait for the other one to finish ? Is this correct ?
If so it brings me to the second part.
Q2. What happens if the first thread dosent finish? Like through an error ? How do I handle this situation ?
Thank you
Yes, calling ThreadLoad_Longer_Data.Join will stop the execution of the calling thread (the one that executes the code calling the Join) till the ThreadLoad_Longer_Data ends its execution.
If, inside ThreadLoad_Longer_Data, you have an unhandled exeception, the result is the ending of the thread and thus the resume of the execution of the calling thread.
Sub Main
Try
Console.WriteLine("Start of the main thread")
Dim ThreadLoad_Longer_Data As Thread
ThreadLoad_Longer_Data = New Thread(AddressOf Me.Fill_LongerSQL)
ThreadLoad_Longer_Data.IsBackground = True
ThreadLoad_Longer_Data.Start()
ThreadLoad_Longer_Data.Join
Console.WriteLine("End of the main thread")
Catch x as Exception
Console.WriteLine(x.Message)
End Try
End Sub
Sub Fill_LongerSQL()
Console.WriteLine("Before the exception")
dim y as integer
for x = 0 to 1000000000
y = y + 1
next
Throw new Exception("This is an unhandled exception")
' this will never executed
Console.WriteLine("After the exception")
End Sub
Related
I use multithreading in my program and I want to create a button to check if any of the threads is still running. If there are no threads running in the background, I want the button to do a specific job like run another thread.
I've written the following code on the button:
If thread1 Or thread2 Or thread3 is Nothing Then
thread2 = New Thread(AddressOf Me.thread2_engine)
thread2.Start()
Else If thread2.IsAlive = True Then
MsgBox("Processing right now, Please wait")
End If
Why can't I use an Or operation inside the if statement?
If use Or like that, you are doing a bitwise Or on the variables. I think what you mean is
If (thread1 Is Nothing) Or (thread2 Is Nothing) Or (thread3 Is Nothing) Then
You might want to use OrElse instead of Or as that will avoid checking the later conditions once one of them is true.
What is the best way to delay code execution in an application while the program is still running?
I've tried this method:
System.Threading.Thread.Sleep()
But the application does not display until the Sleep() has been executed and I am unsure of alternatives.
Dim t = System.Threading.Tasks.Task(Of Boolean).Run(Function() As Boolean
System.Threading.Thread.Sleep(10000)
Return True
End Function)
Dim ret = t.Result
You need to offload this to another thread, if you call sleep on the current thread then everything including the UI is going to wait until sleep has finished. There are multiple ways to achieve this including the example above.
In a project I’ve recently taken over, there is a call to a function which does some calculations; this is called in a row, several times (between 1 and 10 times usually).
While dr.read ‘depending on a db call, loop 1 or more times
Dim calc As New CalcClass
Dim newDoStuff As New System.Threading.Thread(New System.Threading.ParameterizedThreadStart(AddressOf DoStuff))
newDoStuff.Start(calc)
End while
Private Sub DoStuff(ByVal calc As Object)
‘do something that takes between 5-10 seconds
End sub
In order to speed this up, i am trying to add asynchronous processing (see above example), this works in my code, all tasks are done at the same time, but what I don’t understand is how to then wait for all these threads to finish (there is no set amount of threads, it can be between 1 and 10 depending on some other data) before finishing up with a final task that needs to run after all tasks are completed.
Can anyone suggest a way to do this – I’m looking for an easy way to basically say “O.k, all tasks are finished at this point, call another task”
Cliffs
Several tasks need to run at the same time (between 1 and 10)
Each task takes several seconds
Code currently works - it does them all at the same time
Once all tasks (between 1-10) are
finished, fire off some other code (only when all tasks are finished) - stuck on best method to do the following
Put all your thread in an List
Dim threads As new List(Of System.Threading.Thread)
While dr.read ‘depending on a db call, loop 1 or more times
Dim calc As New CalcClass
Dim newDoStuff As New System.Threading.Thread(New System.Threading.ParameterizedThreadStart(AddressOf DoStuff))
threads.Add(newDoStuff)
newDoStuff.Start(calc)
End while
finally join all your threads
For Each thread In threads Do
thread.Join()
Next
The easiest way is to put all of your new threads into a list, then iterate over that list and call .Join() on each one. The join method blocks the current thread until the thread you are Joining completes:
Apologies if there are any syntactic errors in the following code- I don't have VB handy and my memory of the syntax is pretty rusty:
Dim threadList as New List(Of Thread)
While dr.read ‘depending on a db call, loop 1 or more times
Dim calc As New CalcClass
Dim newDoStuff As New System.Threading.Thread(New System.Threading.ParameterizedThreadStart(AddressOf DoStuff))
newDoStuff.Start(calc)
threadList.Add(newDoStuff)
End while
For Each t as Thread in ThreadList
t.Join
End For
With that said, I'd strongly encourage you to look into using the classes in the System.Threading.Tasks namespace, as that provides a much better paradigm than starting and managing your own threads.
Okay so here's the thing:
I have a linq query which loads approx. 1000 lines into a variable, during that process I want to display a progressbar, not necessarily stating the percentage, can be marquee style, doesnt matter.
This progressbar is on a modal form to precent the user from interacting with the app for the time the query's running.
Now here's my code:
Private Sub LoadBar()
Try
Dim load As New frmLoadbar
load.Text = "Loading bunch of data..."
load.ShowDialog()
Catch e As Threading.ThreadAbortException
Threading.Thread.ResetAbort()
End Try
End Sub
In another sub:
Dim myThreadDelegate As New Threading.ThreadStart(AddressOf LoadBar)
Dim th As New Threading.Thread(myThreadDelegate)
th.Name = "TimeConsuming"
th.Start()
Dim XY = db.Table.GetEnumerator
While XY.MoveNext
Dim item As New ListViewItem
item.Text = XY.Current.Name
item.Tag = XY.Current
ListBox1.Items.Add(item)
End While
Autos.Dispose()
Try
th.Abort()
Catch ex As Exception //here's where i 'swallow the re-thrown exception
End Try
Not thats one of the ugliest code i've ever written.It works i just dont want that rethrown exception.
Some explanation:
I want the modal form to close after the query is done.
For that reason I 'abort' the thread running the form.
Since aborting a thread throws a double-exception i have to 'swallow'
that exception.
Now i know i could implement this like the following:
Coding a loop into the form holding the progressbar, which checks
periodically for a boolean's value, and if its true the form could
close itself.
From the other form - on the worker thread - i could change that
booleans value to true after the query's finished.
But here comes my question:
Whats the best way to implement this?
I know it can be done with a background worker, which has been
specifically invented for this reason, but can i use the background
worker as the thread to show the progressbar?
If not (and i have to run the query on the background worker and
showing the modal form from my original form), would that mean that
the query would "work in the background"?
Would that mean that the query would be slower?
I've looked into other tutorials, but for one reason or another, either i wasnt able to copy it (due to complexity) or I wasn't convinced that it was better than this.
Thank you for your time you took to answer.
You could show the modal form and then run a BackgroundWorker from that form. The progress and completed events would be on the UI thread so you can update a progress bar while it is running and close the form in the completed event handler.
Okay, so for future reference, if someone needs clear help with code samples, Microsoft has it (thats a first..)
You can download it here:
Multithreading
Assuming Windows Forms, you do this with a BackgroundWorker component.
In my VB.NET program is a time consuming function that gets data and updates the UI at a periodic interval. I moved this function to another thread, but it now takes much longer to execute. Using the stopwatch class, I calculated that when it is part of the main thread, it takes 130 ms, but in the separate thread it takes 542 ms, so that's more than 4 times slower.
My CPU is a Core I5 M520 (2 cores), so I don't now why is it taking so much longer.
I am using the System.Threading.Thread class. I also tried to set the new thread's priority higher, but this had no effect.
Why is the separate thread taking so much longer and is there a way I can speed it up?
Thanks
The code:
Public Sub update(ByVal temp As Visual)
SyncLock mUpdateQueue
If Not mUpdateQueue.Contains(temp) Then
mUpdateQueue.Enqueue(temp)
End If
End SyncLock
If Not mainThread.IsAlive Then ' moet hierdie beter doen
mainThread = New Thread(AddressOf DataFetchThread)
mainThread.Start()
End If
End Sub
Private Sub DataFetchThread()
Dim s As New Stopwatch()
s.Start()
Dim temp As Visual = Nothing
While mUpdateQueue.Count > 0
SyncLock mUpdateQueue
temp = mUpdateQueue.Peek()
End SyncLock
mDataCollector.updateV(temp)
SyncLock mUpdateQueue
mUpdateQueue.Dequeue()
End SyncLock
End While
s.Stop()
Debug.WriteLine("thread run time: " & s.ElapsedMilliseconds)
End Sub
mDataCollector.updateV(temp): This function get data from a database and plots the points on a picturebox to create a graph. It wouldn't make a lot of sense to add all of the code here.
To ask this question in another way: Is it normal that the second thread takes much longer to execute or is there something wrong with my code?
You are accessing the mUpdateQueue variable from multiple threads and using locks to gaurd access to it. This is fine, but using locks has an overhead (to aquire the lock, and during the time that the other threads wait to aquire the lock). This is probably why your new thread is taking longer: it is waiting on the locking.
You could try using the ReaderWriterLockSlim class which may provide faster access to your variables. Just remember that it implements IDisposable so you need to call Dispose on it when you're done with it.