JedNebula
asked on
Multithreading question
Hi,
I am looking to spin up a new thread and wait for an amount of time before I kill it.
Is this possible to do whilst still allowing UI operations to update?
Below is a small example to show what I am struggling with:
If I rem out the Thread.Join line, then the thread will be aborted after 10 seconds as I desire, but no textbox updates happen.
I would like to both have my cake and eat it if possible...
I am looking to spin up a new thread and wait for an amount of time before I kill it.
Is this possible to do whilst still allowing UI operations to update?
Below is a small example to show what I am struggling with:
Public Class Form1
Sub HitMe()
Do Until 1 = 2
AppendMyText()
Loop
End Sub
Private Sub btn_start(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnstart.Click
Dim thr = New Threading.Thread(AddressOf HitMe)
thr.IsBackground = True
thr.Start()
'thr.Join(10000) 'give it 10 seconds to run
End Sub
Sub AppendMyText()
If Me.InvokeRequired Then
Me.BeginInvoke(New MethodInvoker(Sub() AppendMyText()))
Else
Me.Textbox1.AppendText(Now.ToString & vbNewLine)
Me.Textbox1.ScrollToCaret()
End If
End Sub
End Class
If I rem out the Thread.Join line, then the thread will be aborted after 10 seconds as I desire, but no textbox updates happen.
I would like to both have my cake and eat it if possible...
ASKER
Hi Andy,
Thank you for the reply, but a DoEvents doesn't help because the UI thread is stuck waiting on the Join line.
Regards,
Rawden.
Thank you for the reply, but a DoEvents doesn't help because the UI thread is stuck waiting on the Join line.
Regards,
Rawden.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I did try that, but it didn't seem to quit the thread properly.
Used this example:
http://www.codeproject.com/Questions/528196/SettingplusTimeoutplusinplusvb-net
If someone could put a quick working example together I would be really grateful.
Used this example:
http://www.codeproject.com/Questions/528196/SettingplusTimeoutplusinplusvb-net
If someone could put a quick working example together I would be really grateful.
Before one gets too much in detail this looks to be a very artificial example. Very likely the problem is what I said in my first comment.
If that is the case then would your real requirement have the same problem?
(You do not have to 'join' threads to allow something to be calculated in one thread and have results displayed in the other.)
If that is the case then would your real requirement have the same problem?
(You do not have to 'join' threads to allow something to be calculated in one thread and have results displayed in the other.)
ASKER
HI Andy,
I only tried using the thread.join due to the comments I found here:
http://stackoverflow.com/questions/321779/to-currentthread-abort-or-not-to-currentthread-abort
I did try your suggestion of the DoEvents in my test project, but it didn't make any difference. I can post it online if you like?
I only tried using the thread.join due to the comments I found here:
http://stackoverflow.com/questions/321779/to-currentthread-abort-or-not-to-currentthread-abort
I did try your suggestion of the DoEvents in my test project, but it didn't make any difference. I can post it online if you like?
Here's a working example:
Obviously you were overloading the application, so that's why I added the "If ((i Mod 1000) = 0) Then" to make it slightly more realistic (next time let the while loop be realistic as well as what's inside it..
Public Class Form1
Sub AppendMyText()
If Me.InvokeRequired Then
Me.BeginInvoke(New MethodInvoker(Sub() AppendMyText()))
Else
Me.Textbox1.AppendText(Now.ToString & vbNewLine)
Me.Textbox1.ScrollToCaret()
End If
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
BackgroundWorker1.CancelAsync()
Timer1.Enabled = False
End Sub
Private Sub btnstart_Click(sender As Object, e As EventArgs) Handles btnstart.Click
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.RunWorkerAsync()
Timer1.Enabled = True
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim i = 1
While True
i += 1
If ((i Mod 1000) = 0) Then
AppendMyText()
End If
If (BackgroundWorker1.CancellationPending) Then
e.Cancel = True
Exit While
End If
Application.DoEvents()
End While
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If (e.Cancelled) Then
MsgBox("Canceled")
End If
End Sub
End Class
Obviously you were overloading the application, so that's why I added the "If ((i Mod 1000) = 0) Then" to make it slightly more realistic (next time let the while loop be realistic as well as what's inside it..
OK, looked at that link - so why do you need the join
ASKER
Thank you Kimputer. Just trying your example. Looks good initially. Thank you.
Andy, occasionally my worker routine was 'held up' by some process outside of my control. I need a way to cut it short after an amount of time so that the app can continue to run other tasks.
My real-world app runs some important tasks at 5 am in preparation for the working day when people arrive, but recently the app has been held up on one of the early running tasks and then I have to dial in and kill the errant process it is depending on.
I will spend some time later working out why the external resource was taking much longer than expected, but this question is about putting a fail-safe in place.
Andy, occasionally my worker routine was 'held up' by some process outside of my control. I need a way to cut it short after an amount of time so that the app can continue to run other tasks.
My real-world app runs some important tasks at 5 am in preparation for the working day when people arrive, but recently the app has been held up on one of the early running tasks and then I have to dial in and kill the errant process it is depending on.
I will spend some time later working out why the external resource was taking much longer than expected, but this question is about putting a fail-safe in place.
>>I need a way to cut it short after an amount of time so that the app can continue to run other tasks.
If a thread is running/stopped that should have no effect on the rest of the app. If it does then it sounds like the interaction between the thread and the UI app is problematic. (The thread forces the app to stop or the app is stopped to wait for the thread - either way is bad programming).
If a thread is running/stopped that should have no effect on the rest of the app. If it does then it sounds like the interaction between the thread and the UI app is problematic. (The thread forces the app to stop or the app is stopped to wait for the thread - either way is bad programming).
ASKER
Although I am running a multi-threaded application, I still only fire off one task at a time. So if one takes longer than it should, the rest of the app doesn't hang - the UI still responds, but the app is waiting for that thread to finish before it can fire off another.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I don't think join is really the right method for me to use either. I only tried it because it recommended it in that article and I have to confess I only skim-read it. I was just looking for a thread.wait(x) method really, but that is what join seemed to do.
I think I have found a working solution now. I'll post it in a sec.
I think I have found a working solution now. I'll post it in a sec.
ASKER
My working code:
Imports System.ComponentModel
Public Class Form1
Private WithEvents tmr As Timer
Private t As Threading.Thread
Sub AppendMyText(text As String)
If Me.Textbox1.IsDisposed Then Exit Sub
If Me.Textbox1.InvokeRequired Then
Me.Textbox1.BeginInvoke(New MethodInvoker(Sub() AppendMyText(text)))
Else
Me.Textbox1.AppendText(text & vbNewLine)
Me.Textbox1.ScrollToCaret()
End If
End Sub
Sub TheWork()
Dim tc As Long
Dim counter As Long
While True
tc = Environment.TickCount
If tc Mod 1000 = 0 Then
If tc <> counter Then
counter = tc
AppendMyText(Now.ToString)
End If
End If
Application.DoEvents()
End While
End Sub
Private Sub btnstart_Click(sender As Object, e As EventArgs) Handles btnstart.Click
t = New Threading.Thread(AddressOf TheWork)
t.IsBackground = True
t.Start()
tmr = New Timer
tmr.Interval = 15000
tmr.Enabled = True
End Sub
Private Sub tmr_Tick(sender As Object, e As EventArgs) Handles tmr.Tick
tmr.Enabled = False
If t IsNot Nothing Then
t.Abort()
t = Nothing
Textbox1.Clear()
End If
End Sub
End Class
Sub HitMe()
Do Until 1 = 2
AppendMyText()
DoEvents
Loop
End Sub