rwallacej
asked on
Background Worker thread problem
I've got a progress form with ok/cancel button. If user clicks cancel the background thread stops
However, if they try to rerun process again from scratch by clicking OK to restart it there's an error
A first chance exception of type 'System.InvalidOperationEx ception' occurred in System.dll
CalculateToolStripMenuItem _Click_1 at System.ComponentModel.Back groundWork er.RunWork erAsync(Ob ject argument)
at System.ComponentModel.Back groundWork er.RunWork erAsync()
at PIEE_Energy_and_GHG_Foreca ster.Progr essForm.Bu tton1_Clic k(Object sender, EventArgs e) in E:\Backup VAIO 2 (USE INSTEAD OF HD)\PIEE Energy and GHG Forecaster\PIEE Energy and GHG Forecaster\ProgressForm.vb :line 58
LINE 58 of progress form does
Form1.BackgroundWorker1.Ru nWorkerAsy nc()
Help please!!!
However, if they try to rerun process again from scratch by clicking OK to restart it there's an error
A first chance exception of type 'System.InvalidOperationEx
CalculateToolStripMenuItem
at System.ComponentModel.Back
at PIEE_Energy_and_GHG_Foreca
LINE 58 of progress form does
Form1.BackgroundWorker1.Ru
Help please!!!
ASKER
code that does lots of work
For x = 1 To MAX
If worker.CancellationPending Then
Exit Sub
'probably need more in here?
Else
do the calcs
End if
For x = 1 To MAX
If worker.CancellationPending
Exit Sub
'probably need more in here?
Else
do the calcs
End if
ASKER
Private Sub BackgroundWorker1_DoWork(B yVal sender As System.Object, ByVal e As System.ComponentModel.DoWo rkEventArg s) Handles BackgroundWorker1.DoWork
Try
Debug.Print("Background worker Form1")
Dim worker As System.ComponentModel.Back groundWork er = CType(sender, System.ComponentModel.Back groundWork er)
bigmethod(worker)
Catch ex As Exception
utils.ExceptionLog(ex)
End Try
End Sub
Try
Debug.Print("Background worker Form1")
Dim worker As System.ComponentModel.Back
bigmethod(worker)
Catch ex As Exception
utils.ExceptionLog(ex)
End Try
End Sub
ASKER
Private Sub BackgroundWorker1_RunWorke rCompleted (ByVal sender As System.Object, ByVal e As System.ComponentModel.RunW orkerCompl etedEventA rgs) Handles BackgroundWorker1.RunWorke rCompleted
Try
ProgressForm.Close() 'doesn't close right?
ProgressForm.Visible = False
If Not e.Cancelled Then
OutputTable.ShowDialog()
Else
MsgBox("Cancelled calculations!")
End If
Catch ex As Exception
Utils.ExceptionLog(ex)
End Try
End Sub
Private Sub BackgroundWorker1_Progress Changed(By Val sender As System.Object, ByVal e As System.ComponentModel.Prog ressChange dEventArgs ) Handles BackgroundWorker1.Progress Changed
Try
Debug.Print("Progress...." )
ProgressForm.ProgressBar1. Value = e.ProgressPercentage
ProgressForm.ProgressLabel .Text = ProgressStatus
If e.ProgressPercentage = 92 Then
ProgressForm.ProgressLabel .Text = "Finalising Stage"
End If
Catch ex As Exception
Utils.ExceptionLog(ex)
End Try
End Sub
Try
ProgressForm.Close() 'doesn't close right?
ProgressForm.Visible = False
If Not e.Cancelled Then
OutputTable.ShowDialog()
Else
MsgBox("Cancelled calculations!")
End If
Catch ex As Exception
Utils.ExceptionLog(ex)
End Try
End Sub
Private Sub BackgroundWorker1_Progress
Try
Debug.Print("Progress...."
ProgressForm.ProgressBar1.
ProgressForm.ProgressLabel
If e.ProgressPercentage = 92 Then
ProgressForm.ProgressLabel
End If
Catch ex As Exception
Utils.ExceptionLog(ex)
End Try
End Sub
So, how exectly do you cancel background thread when use clicks Cancel button?
ASKER
here it is:
Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click
Form1.BackgroundWorker1.Ca ncelAsync( )
Me.DialogResult = System.Windows.Forms.Dialo gResult.Ca ncel
Me.Close()
End Sub
Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click
Form1.BackgroundWorker1.Ca
Me.DialogResult = System.Windows.Forms.Dialo
Me.Close()
End Sub
Form1.BackgroundWorker1.Ca ncelAsync( )
This is OK. You asked background worker to exit. But this doesn't mean that it exits immediately. It can continue to work.
For x = 1 To MAX
If worker.CancellationPending Then
Exit Sub ' this is OK
Else
do the calcs
End if
Looks OK, but how much time "do the calcs" part executes? If it takes, for example, 10 seconds, background thread doesn't stop immediately. Test CancellationPending in more places to ensure fast response to cancellation request.
Let's return to CancelAsync line. It executes and continues immediately, without waiting for actual thread exit. You cal add code to wait for this:
Form1.BackgroundWorker1.Ca ncelAsync( )
while ( Form1.BackgroundWorker1.Is Busy )
Thread.Sleep(100)
end while
Another way is to disable Start button when BackgroundWorker starts, and subscribe to BackgroundWorker.RunWorker Completed event. In event handler enable Start button. This ensures that Start button cannot be pressed while BackgroundWorker is busy.
This is OK. You asked background worker to exit. But this doesn't mean that it exits immediately. It can continue to work.
For x = 1 To MAX
If worker.CancellationPending
Exit Sub ' this is OK
Else
do the calcs
End if
Looks OK, but how much time "do the calcs" part executes? If it takes, for example, 10 seconds, background thread doesn't stop immediately. Test CancellationPending in more places to ensure fast response to cancellation request.
Let's return to CancelAsync line. It executes and continues immediately, without waiting for actual thread exit. You cal add code to wait for this:
Form1.BackgroundWorker1.Ca
while ( Form1.BackgroundWorker1.Is
Thread.Sleep(100)
end while
Another way is to disable Start button when BackgroundWorker starts, and subscribe to BackgroundWorker.RunWorker
ASKER
Compile time says "thread is not declared"
ASKER
The "do the calcs" bit can take up to 5 mins :-(
ASKER
its System.Threading.Thread.Sl eep(100) - OK
If do the calcs" bit can take up to 5 mins , you must add CancellationPending tests to this code to ensure fast reaction to caclellation request.
ASKER
Form1.BackgroundWorker1.Is Busy always seems to be true - so its never stopping (I added a debug line before thread.sleep to check it was still going)
I've added If worker.CancellationPending Then
Exit Sub ' this is OK
test in more places on the calculation
More help needed I'm afraid...thanks for help so far!
I've added If worker.CancellationPending
Exit Sub ' this is OK
test in more places on the calculation
More help needed I'm afraid...thanks for help so far!
Replace "do the calcs" with something short (1-2 seconds) for testing, and you will see that IsBusy is changed to false relatively fast. Having this working, return to initial version and add more tests for CancellationPending to the code.
ASKER
here's the score now...
OK button
Form1.BackgroundWorker1.Ru nWorkerAsy nc()
Cancel button
Debug.Print("Cancelling... .")
Form1.BackgroundWorker1.Ca ncelAsync( )
While (Form1.BackgroundWorker1.I sBusy)
System.Threading.Thread.Sl eep(100)
End While
Debug.Print("Reached end of cancel...closing form") 'NEVER GETS TO HERE!
Me.DialogResult = System.Windows.Forms.Dialo gResult.Ca ncel
Me.Close()
Private Sub BackgroundWorker1_DoWork(B yVal sender As System.Object, ByVal e As System.ComponentModel.DoWo rkEventArg s) Handles BackgroundWorker1.DoWork
Try
Debug.Print("Background worker Form1")
Dim worker As System.ComponentModel.Back groundWork er = CType(sender, System.ComponentModel.Back groundWork er)
bigMethod(worker, AxSpreadsheet1) 'ExcelObjects.ExcelApp, worker, ExcelObjects.ThisWorkbook)
Catch ex As Exception
Debug.Print("BackgroundWor ker1_DoWor k " & ex.StackTrace)
utils.ExceptionLog(ex)
End Try
End Sub
bigMethod
Public Sub bigMethod(ByVal worker As System.ComponentModel.Back groundWork er, ByRef axs As AxOWC10.AxSpreadsheet)
For x = 1 To MAX
If worker.CancellationPending Then
Exit Sub
Else
Dim x As Integer
For x = 0 To 5000
If worker.CancellationPending Then
Exit Sub
Else
Debug.Print("col = " & x)
End If
Next
'my big calculation was here but I removed it
end if
end for
...still never stopping when I click Cancel :-(
probably something stupid I'm doing but don't see what
OK button
Form1.BackgroundWorker1.Ru
Cancel button
Debug.Print("Cancelling...
Form1.BackgroundWorker1.Ca
While (Form1.BackgroundWorker1.I
System.Threading.Thread.Sl
End While
Debug.Print("Reached end of cancel...closing form") 'NEVER GETS TO HERE!
Me.DialogResult = System.Windows.Forms.Dialo
Me.Close()
Private Sub BackgroundWorker1_DoWork(B
Try
Debug.Print("Background worker Form1")
Dim worker As System.ComponentModel.Back
bigMethod(worker, AxSpreadsheet1) 'ExcelObjects.ExcelApp, worker, ExcelObjects.ThisWorkbook)
Catch ex As Exception
Debug.Print("BackgroundWor
utils.ExceptionLog(ex)
End Try
End Sub
bigMethod
Public Sub bigMethod(ByVal worker As System.ComponentModel.Back
For x = 1 To MAX
If worker.CancellationPending
Exit Sub
Else
Dim x As Integer
For x = 0 To 5000
If worker.CancellationPending
Exit Sub
Else
Debug.Print("col = " & x)
End If
Next
'my big calculation was here but I removed it
end if
end for
...still never stopping when I click Cancel :-(
probably something stupid I'm doing but don't see what
Is BackgroundWorker.WorkerSup portsCance llation Property set to true?
ASKER
yes, it sure is
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
This is my test. It contains Windows Form with two buttons: btsStart and btnStop, and BackgroundWorker1 with WorkerSupportsCancellation property = true. This is the code:
Imports System.Diagnostics
Imports System.Threading
Public Class Form1
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
BackgroundWorker1.RunWorke rAsync()
btnStart.Enabled = False
End Sub
Private Sub BackgroundWorker1_DoWork(B yVal sender As Object, ByVal e As System.ComponentModel.DoWo rkEventArg s) Handles BackgroundWorker1.DoWork
Dim worker As System.ComponentModel.Back groundWork er = CType(sender, System.ComponentModel.Back groundWork er)
Dim n As Integer = 0
While (True)
If worker.CancellationPending = True Then
Trace.WriteLine("Cancelled - exit")
Exit Sub
End If
Thread.Sleep(300)
Trace.WriteLine(n.ToString )
n = n + 1
End While
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
If BackgroundWorker1.IsBusy = False Then
Return
End If
BackgroundWorker1.CancelAs ync()
While (True)
If BackgroundWorker1.IsBusy Then
Exit While
End If
Trace.WriteLine("Waiting.. .")
Thread.Sleep(100)
End While
Trace.WriteLine("Thread exited")
btnStart.Enabled = True
End Sub
End Class
Imports System.Diagnostics
Imports System.Threading
Public Class Form1
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
BackgroundWorker1.RunWorke
btnStart.Enabled = False
End Sub
Private Sub BackgroundWorker1_DoWork(B
Dim worker As System.ComponentModel.Back
Dim n As Integer = 0
While (True)
If worker.CancellationPending
Trace.WriteLine("Cancelled
Exit Sub
End If
Thread.Sleep(300)
Trace.WriteLine(n.ToString
n = n + 1
End While
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
If BackgroundWorker1.IsBusy = False Then
Return
End If
BackgroundWorker1.CancelAs
While (True)
If BackgroundWorker1.IsBusy Then
Exit While
End If
Trace.WriteLine("Waiting..
Thread.Sleep(100)
End While
Trace.WriteLine("Thread exited")
btnStart.Enabled = True
End Sub
End Class
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Show your code - how do you cancel background thread.
Simple solution can be creating new BackgroundWorker instance every time. However, thread should be stopped in any case.