线程:Invoke卡住.NET

时间:2016-03-20 19:05:49

标签: vb.net multithreading invoke invokerequired

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

  • 开始
  • 重新启动
  • 停止

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

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

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

gAppExit是一个全局变量,用于指示用户是否已通过“退出”工具线程设备退出应用程序。

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

当用户想要重新启动后台线程时,他点击了restart toolstripmenuitem并完成了以下序列(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

请注意,在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中启用启动toolstripmenuitem并禁用restart并停止toolstripmenuitems。

问题是:

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

MainMenu.Invoke(New ChangeStatusToStoppedDelegate(AddressOf ChangeStatusToStopped))

然后它卡在那里,也就是身体:

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

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

我看过那行:

Me.ThreadBgWorker.Join()

在后台线程退出主循环之前已达到WaitFinish()函数中的

,并且在执行Me.ThreadBgWorker.Join()之前已将thdExit设置为true,一旦执行了连接,应用程序就会卡住,后台线程无法退出主循环(似乎应用程序正在忙碌或冻结。)

0 个答案:

没有答案