2

我有一个系统托盘应用程序。托盘应用程序有一个图标和一个带有一些选项的上下文菜单。有一个名为 status 的菜单,其中包含以下工具条菜单项:

  • 开始
  • 重新开始
  • 停止

它们根据某些条件启用/禁用。

我的系统托盘应用程序有一个后台线程,它会不断检查一些条件并做一些工作。它的主循环如下:

Do Until gAppExit Or Me.thdExit
 ' Check some conditions and do some work
Loop

gAppExit 是一个全局变量,指示用户是否已通过“退出”工具条菜单项退出应用程序。

thdExit 表示线程是否应该退出循环(我稍后解释)。

当用户想要重新启动后台线程时,他单击重新启动工具条菜单并完成以下顺序(重新启动->暂停->等待完成):

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

请注意,在 Halt 函数上,它通过在函数 WaitFinish 上调用 Me.ThreadBgWorker.Join() 来等待线程完成。在调用 WaitFinish 函数之前,将 thdExit 设置为 true,以便后台线程可以退出主循环:

Do Until gAppExit Or Me.thdExit
 ' Check some conditions and do some work
Loop

ChangeStatusToStopped()

在退出循环时,调用 ChangeStatusToStopped(),如下所示:

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

它的作用是在 UI 中启用启动工具条菜单项并禁用重新启动和停止工具条菜单项。

问题是:

在 ChangeStatusToStopped 方法中,当 MainMenu.InvokeRequired 为 true 时,它​​调用:

MainMenu.Invoke(New ChangeStatusToStoppedDelegate(AddressOf ChangeStatusToStopped))

然后它就卡在那里了,也就是说,else body:

        Me.submnuStart.Enabled = True
        Me.submnuReStart.Enabled = False
        Me.submnuStop.Enabled = False

永远不会被执行。似乎主线程很忙或消息泵中的其他问题....有什么想法吗?

我看到了那条线:

Me.ThreadBgWorker.Join()

在后台线程退出主循环之前到达 WaitFinish() 函数,尽管在执行 Me.ThreadBgWorker.Join() 之前已将 thdExit 设置为 true,但一旦执行连接,应用程序就会卡住,后台线程无法退出主循环(似乎应用程序是忙或冻结)。

4

0 回答 0