Solved

Multithreading question

Posted on 2015-02-19
14
90 Views
Last Modified: 2015-02-19
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:

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

Open in new window


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...
0
Comment
Question by:JedNebula
  • 7
  • 5
  • 2
14 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40618672
I suspect you just aren't giving the UI a chance to update because of the continual changing of the text - give something like the following a try.  It might need some adjustment with the DoEvents call.

Sub HitMe()

        Do Until 1 = 2
            AppendMyText()
DoEvents
        Loop

    End Sub
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40618684
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.
0
 
LVL 35

Accepted Solution

by:
Kimputer earned 250 total points
ID: 40618748
How about using Timers (for both the Do Until madness, as well as the stopping at 10 seconds)
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 1

Author Comment

by:JedNebula
ID: 40618761
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.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40618820
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.)
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40618839
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?
0
 
LVL 35

Expert Comment

by:Kimputer
ID: 40618842
Here's a working example:

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

Open in new window


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..
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40618866
OK, looked at that link - so why do you need the join
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40618894
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.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40619010
>>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).
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40619021
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.
0
 
LVL 44

Assisted Solution

by:AndyAinscow
AndyAinscow earned 250 total points
ID: 40619116
>>but the app is waiting for that thread to finish before it can fire off another.

So the tasks have to be run one after the other.  I still don't understand the need to 'join'.  When you want to spawn the second (or third....) you seem to say you check the state of the previous thread.  
If it is still running you can force it to finish (not really recommended) with the Abort command.  It is better to put some sort of flag condition so the thread will exit from it's loop (assuming it is in a loop for the calculation) and hence terminate itself.

This is C# but the principle is the same:
https://msdn.microsoft.com/en-us/library/7a2f3ay4.aspx
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40619127
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.
0
 
LVL 1

Author Comment

by:JedNebula
ID: 40619133
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

Open in new window

0

Featured Post

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question