I have a system tray application. The tray application has an icon and a context menu with some options. There is a menu called status which contains below toolstripmenuitems:
- Start
- Restart
- Stop
They are enabled/disabled according to some conditions.
My system tray application, has a background thread does continuously check some conditions and do some work. Its main loop is below:
Do Until gAppExit Or Me.thdExit
' Check some conditions and do some work
Loop
gAppExit is a global variable that indicates whether user has exited from application through the 'exit' toolstripmenuitem.
thdExit indicates whether the thread should exit from the loop (I explain it later).
When user want to restart the background thread, he clicks on restart toolstripmenuitem and below sequence is done (Restart -> Halt -> WaitFinish):
Public Function ReStart() As Integer
Dim result As Integer
If IsNothing(ThreadBgWorker) Then
Logger.Write("Task is not yet created!", LOGGING_CRITICAL_ERRORS_CATEGORY)
Return RESULT_ERROR
End If
result = Me.Halt()
If result <> RESULT_ERROR Then
result = Me.Start()
End If
Return result
End Function
Public Function Halt() As Integer
Dim result As Integer
If IsNothing(ThreadBgWorker) Then
Logger.Write("Task is not yet created!", LOGGING_CRITICAL_ERRORS_CATEGORY)
Return RESULT_ERROR
End If
Me.thdExit = True
result = Me.WaitFinish()
Return result
End Function
Public Function WaitFinish() As Integer
Dim result As Integer
If IsNothing(ThreadBgWorker) Then
Return RESULT_ERROR
End If
result = RESULT_ERROR
Try
'TODO:
Console.WriteLine("Wait thread to finish (before Join)...")
Me.ThreadBgWorker.Join()
'TODO:
Console.WriteLine("Thread finished... Continue restarting thread...")
Me.RetVal = True
result = Me.ThreadBgWorker.ManagedThreadId
Logger.Write(String.Format("Task ""{0}"" correctly stopped.", _
Me.ThreadBgWorker.Name))
Catch ex As Exception
Logger.Write(String.Format("Couldn't stop task ""{0}"": {1}", _
Me.ThreadBgWorker.Name, ex.Message), _
LOGGING_CRITICAL_ERRORS_CATEGORY)
End Try
Return result
End Function
Public Function Start() As Integer
Dim result As Integer
If IsNothing(ThreadBgWorker) Then
Logger.Write("Task is not yet created!", LOGGING_CRITICAL_ERRORS_CATEGORY)
Return RESULT_ERROR
End If
result = RESULT_ERROR
Me.thdExit = False
Try
If Me.ThreadBgWorker.ThreadState = Threading.ThreadState.Stopped Then
Me.Create()
End If
Me.ThreadBgWorker.Start() ' Start the new thread.
result = Me.ThreadBgWorker.ManagedThreadId
Logger.Write(String.Format("Task ""{0}"" correctly started.", _
Me.ThreadBgWorker.Name))
Catch ex As Exception
Logger.Write(String.Format("Couldn't start task ""{0}"": {1}", _
Me.ThreadBgWorker.Name, ex.Message), _
LOGGING_CRITICAL_ERRORS_CATEGORY)
End Try
Return result
End Function
Note that on Halt function, it awaits thread to finish by calling Me.ThreadBgWorker.Join() on function WaitFinish. Before calling WaitFinish function, thdExit is set to true in order to background thread can exit from main loop:
Do Until gAppExit Or Me.thdExit
' Check some conditions and do some work
Loop
ChangeStatusToStopped()
on exit loop, ChangeStatusToStopped() is called, and it is as below:
Private Delegate Sub ChangeStatusToStoppedDelegate()
Public Sub ChangeStatusToStopped()
' TODO:
Console.WriteLine("Changing status to stopped...")
System.Windows.Forms.Application.DoEvents()
If MainMenu.InvokeRequired Then
'TODO:
Console.WriteLine("Invoke required!")
MainMenu.Invoke(New ChangeStatusToStoppedDelegate(AddressOf ChangeStatusToStopped))
Else
'TODO:
Console.WriteLine("Invoke NOT required!")
Me.submnuStart.Enabled = True
Me.submnuReStart.Enabled = False
Me.submnuStop.Enabled = False
End If
' TODO:
Console.WriteLine("Status changed to stopped.")
End Sub
What it does is to enable Start toolstripmenuitem and disable restart and stop toolstripmenuitems in the UI.
The problem is:
Within ChangeStatusToStopped method, when MainMenu.InvokeRequired is true, it calls:
MainMenu.Invoke(New ChangeStatusToStoppedDelegate(AddressOf ChangeStatusToStopped))
and then it gets stuck there, that is, else body:
Me.submnuStart.Enabled = True
Me.submnuReStart.Enabled = False
Me.submnuStop.Enabled = False
is never executed. It seems like main thread is busy or some other problem in message pump.... Any ideas?
I have seen that line:
Me.ThreadBgWorker.Join()
in WaitFinish() function is reached before background thread exits main loop and despite thdExit has been set to true before doing Me.ThreadBgWorker.Join(), once join is performed, application gets stuck, background thread cannot exit main loop (seems application is busy or frozen).