1

我看过很多关于控制问题的帖子。调用挂起的应用程序,但它们似乎大多仅限于在 .NET 1.1 上运行的应用程序。我还看到了使用 .BeginInvoke 的建议,我尝试过但无济于事。.BeginInvoke 不会挂起,但它也不会调用委托。我主要担心的是我已经使用 .Invoke 多年没有任何问题,并且我在该领域有一个广泛使用它的主要应用程序,我担心这个问题会在那里出现。据我所知,我的工作代码和失败的代码之间没有什么不同。我写了一段简单的代码来复制这个问题(全部在 4.0 VS2010 中):

Public Class Form1

    Private WithEvents sat As TestInvoke
    Private Delegate Sub doTheUpdateDelegate(ByVal message As String)

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles     Button1.Click
        sat = New TestInvoke

        sat.startAThread()

    End Sub

    Public Class TestInvoke

        Public Event UpdateControl()

        Public Sub startAThread()
            Dim t As New Threading.Thread(AddressOf _startAThread)
            Dim trace As String

            trace = "a"
            t.SetApartmentState(Threading.ApartmentState.STA)

            t.Start()
            t.Join()

        End Sub

        Protected Sub _startAThread()
            Try
                For k = 0 To 10
                    System.Threading.Thread.Sleep(1000)
                    k += 1
                    RaiseEvent UpdateControl()
                Next
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        End Sub
    End Class

    Private Sub sat_UpdateControl() Handles sat.UpdateControl
        Try
            Call doTheupdate(Now.ToString)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    Private Sub doTheUpdate(ByVal message As String)
        Try
            If Button1.InvokeRequired = True Then
                Dim objParams As Object() = {message}

                'hangs on the following line
                Button1.Invoke(New doTheUpdateDelegate(AddressOf doTheUpdate),     objParams)

            Else
                Button1.Text = message
            End If
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
End Class

如果有人能看到我在这里做错了什么,我将不胜感激!

4

2 回答 2

11

Control.Invoke() 调用挂起的原因只有一个。或者 BeginInvoke() 调用不执行其目标,同样的事情。当程序的主线程 UI 线程没有空闲并忙于做其他事情时,就会发生这种情况。

“其他东西”可能是地图。您可以做的最糟糕的事情是让主线程等待工作线程完成。如果您使用 Invoke(),那肯定会出现死锁。

这种情况很容易诊断,使用 Debug + Break All 和 Debug + Windows + Threads。双击主线程并查看调用堆栈窗口。堆栈跟踪的顶部应该是“Managed to Native Transition”,它下面的应该是 FPushMessageLoop()。如果您看到其他内容,那么您已经找到了导致死锁的代码。

于 2012-10-25T22:44:00.707 回答
1

您正在使用Thread.Join让 UI 线程暂停,直到另一个线程完成。同时你Control.Invoke用来让 UI 线程做一些动作。这不起作用,因为 UI 线程正在等待另一个线程完成。

Thread.Join如果您希望它等待操作完成,我建议您删除呼叫或在 UI 线程中执行您的操作。

于 2012-10-25T22:44:53.887 回答