Control.Invoke is hanging

2019-01-15 17:26发布

I've seen a ton of post regarding the problem of control.Invoke hanging applications but they mostly seemed to be restricted to those running on .NET 1.1. I've also seen suggestions to use .BeginInvoke instead which I have tried but to no avail. .BeginInvoke doesn't hang but it also doesn't call the delegate. My main concern is that I have used .Invoke for years with no issues and I have a major application in the field that uses it extensively and I'm worried that this problem will crop up there. I am doing nothing differently as far as I can tell between my working code and the code that fails. I've written up a dead simple bit of code that replicates the issue (all in 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

If anyone can see what I've done wrong here I'd really appreciate it!

2条回答
闹够了就滚
2楼-- · 2019-01-15 17:37

You are using Thread.Join to let the UI thread pause until the other thread is done. At the same time you use Control.Invoke to let the UI thread do some action. This won't work because the UI thread is waiting for the other thread to finish.

I would suggest you either remove the Thread.Join call or do your action in the UI thread if you want it to wait for the action to finish.

查看更多
疯言疯语
3楼-- · 2019-01-15 17:59

There's only one reason a Control.Invoke() call would hang. Or a BeginInvoke() call not executing its target, same thing. It happens when the main thread of the program, the UI thread, is not idle and busy doing something else.

What the "something else" could be is all over the map. The worst thing you could do have the main thread wait for the worker thread to complete. That's a guaranteed deadlock if you use Invoke().

The condition is very easy to diagnose, use Debug + Break All and Debug + Windows + Threads. Double-click the Main thread and look at the Call Stack window. The top of the stack trace should say "Managed to Native Transition", the one below it should be FPushMessageLoop(). If you see something else then you've found the code that causes the deadlock.

查看更多
登录 后发表回答