G
Guest
How to stop a process which is running in a separate thread!!!
I've got a class which performs some lengthy process in a background
(separate) thread. And this lengthy process raises events regularly to inform
the main thread of the progress (which is then displayed to the user).
Since the event is raised from another thread, i've used me.Invoke() to
update the ui properly.
However, my problem is in cancelling the process.
I need to be able to execute a method such as Cancel() which will return
only when the process has been cancelled.
Below is the code i've implemented.
How ever, the WaitOne() method will ALWAYS return FALSE.
I'm assuming this is becuase the WaitOne causes the current thread to wait
untill it receives a signal. & since the current thread is also in the
process of updating the UI, the background process thread is not able to send
the signal.
Hence a dead lock (if not for the timeout in the WaitOne())
I'm sure this HAS to be possible.
I need a mechanism to cancel the background process and WAIT till it
confirms that the process has been cancelled (i.e. wait till the process
notifies the main thread that the process has been cancelled).
How can this be done?
Below is a sample the code which outlies the above issue:
Public Class frmThreads
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Label1 As System.Windows.Forms.Label
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Label1 = New System.Windows.Forms.Label
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(40, 120)
Me.Button1.Name = "Button1"
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(128, 120)
Me.Button2.Name = "Button2"
Me.Button2.TabIndex = 1
Me.Button2.Text = "Button2"
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(32, 24)
Me.Label1.Name = "Label1"
Me.Label1.TabIndex = 2
Me.Label1.Text = "Label1"
'
'frmThreads
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Name = "frmThreads"
Me.Text = "frmThreads"
Me.ResumeLayout(False)
End Sub
#End Region
Private _lengthyProcess As LengthyProcess
Private _counter As Integer
Private dlgIvokeProgress As New dlgProgress(AddressOf ShowProgress)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
_lengthyProcess = New LengthyProcess
AddHandler _lengthyProcess.Progress, AddressOf LengthyProcess_Progress
Dim start As New Threading.Thread(AddressOf StartProcess)
start.Start()
End Sub
Private Sub StartProcess()
_lengthyProcess.Start()
End Sub
Private Sub LengthyProcess_Progress(ByVal counter As Integer)
_counter = counter
Me.Invoke(dlgIvokeProgress)
End Sub
Private Delegate Sub dlgProgress()
Private Sub ShowProgress()
Me.Label1.Text = _counter
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
MsgBox(_lengthyProcess.Cancel)
End Sub
End Class
Public Class LengthyProcess
Public Event Progress(ByVal counter As Integer)
Private _counter As Integer
Private _cancelled As Boolean
Private _stopped As Threading.ManualResetEvent
Public Sub Start()
Do While _cancelled = False
_counter += 1
Threading.Thread.Sleep(100)
RaiseEvent Progress(_counter)
Loop
If _cancelled = True Then
_stopped.Set()
End If
End Sub
Public Function Cancel() As Boolean
_stopped = New Threading.ManualResetEvent(False)
_cancelled = True
'this will ALWAYS return FALSE
'how ever if i were to display a messagebox here and THEN
'execute the WaitOne(), it will return TRUE
'MsgBox("WaitOne will now return TRUE")
Return _stopped.WaitOne(5000, False)
End Function
End Class
I've got a class which performs some lengthy process in a background
(separate) thread. And this lengthy process raises events regularly to inform
the main thread of the progress (which is then displayed to the user).
Since the event is raised from another thread, i've used me.Invoke() to
update the ui properly.
However, my problem is in cancelling the process.
I need to be able to execute a method such as Cancel() which will return
only when the process has been cancelled.
Below is the code i've implemented.
How ever, the WaitOne() method will ALWAYS return FALSE.
I'm assuming this is becuase the WaitOne causes the current thread to wait
untill it receives a signal. & since the current thread is also in the
process of updating the UI, the background process thread is not able to send
the signal.
Hence a dead lock (if not for the timeout in the WaitOne())
I'm sure this HAS to be possible.
I need a mechanism to cancel the background process and WAIT till it
confirms that the process has been cancelled (i.e. wait till the process
notifies the main thread that the process has been cancelled).
How can this be done?
Below is a sample the code which outlies the above issue:
Public Class frmThreads
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Label1 As System.Windows.Forms.Label
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Label1 = New System.Windows.Forms.Label
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(40, 120)
Me.Button1.Name = "Button1"
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(128, 120)
Me.Button2.Name = "Button2"
Me.Button2.TabIndex = 1
Me.Button2.Text = "Button2"
'
'Label1
'
Me.Label1.Location = New System.Drawing.Point(32, 24)
Me.Label1.Name = "Label1"
Me.Label1.TabIndex = 2
Me.Label1.Text = "Label1"
'
'frmThreads
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.Label1)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Name = "frmThreads"
Me.Text = "frmThreads"
Me.ResumeLayout(False)
End Sub
#End Region
Private _lengthyProcess As LengthyProcess
Private _counter As Integer
Private dlgIvokeProgress As New dlgProgress(AddressOf ShowProgress)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
_lengthyProcess = New LengthyProcess
AddHandler _lengthyProcess.Progress, AddressOf LengthyProcess_Progress
Dim start As New Threading.Thread(AddressOf StartProcess)
start.Start()
End Sub
Private Sub StartProcess()
_lengthyProcess.Start()
End Sub
Private Sub LengthyProcess_Progress(ByVal counter As Integer)
_counter = counter
Me.Invoke(dlgIvokeProgress)
End Sub
Private Delegate Sub dlgProgress()
Private Sub ShowProgress()
Me.Label1.Text = _counter
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
MsgBox(_lengthyProcess.Cancel)
End Sub
End Class
Public Class LengthyProcess
Public Event Progress(ByVal counter As Integer)
Private _counter As Integer
Private _cancelled As Boolean
Private _stopped As Threading.ManualResetEvent
Public Sub Start()
Do While _cancelled = False
_counter += 1
Threading.Thread.Sleep(100)
RaiseEvent Progress(_counter)
Loop
If _cancelled = True Then
_stopped.Set()
End If
End Sub
Public Function Cancel() As Boolean
_stopped = New Threading.ManualResetEvent(False)
_cancelled = True
'this will ALWAYS return FALSE
'how ever if i were to display a messagebox here and THEN
'execute the WaitOne(), it will return TRUE
'MsgBox("WaitOne will now return TRUE")
Return _stopped.WaitOne(5000, False)
End Function
End Class