无限循环和交叉线程

时间:2011-06-22 19:31:58

标签: vb.net multithreading visual-studio-2008 stack-overflow

我是一名学生,试图自己学习VB.NET。今天我想解决BackgroundWorker组件。我在网上找到了一篇很好的文章:How To Use a Background Worker。我成功地完成了演练,甚至执行了“冒险”部分,该部分涉及使用委托使用控件更新线程。

现在我找到了一个我不明白它是如何工作的部分。总结以下代码,我有一个委托,其签名中有一个Label和一个String。然后我有一个在工作线程上调用的子例程。在这个子例程中,创建了委托,并且(我猜)再次运行,以便它在同一个(主)线程上。如果我错了,请纠正我。

以下是在工作线程上执行的方法:

    Private Sub My_BgWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles My_BGWorker.DoWork

        SetLabelText_ThreadSafe(Me.lbl_Status, FormatPercent(i / m_CountTo, 2))

End Sub

我只包含了对这个问题很重要的代码行。如你所见,然后调用我提到的子程序:

    Private Sub SetLabelText_ThreadSafe(ByVal lbl As Label, ByVal txt As String)
    ' InvokeRequired required compares the thread ID of the calling thread to the thread ID of the creating thread.
    ' If these threads are different, it returns true.
    If lbl.InvokeRequired Then
        'WORKS: Dim MyDelegate As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)
        'WORKS: Me.Invoke(MyDelegate, New Object() {lbl, txt})
        MyDel.Invoke(lbl, txt)
    Else
        lbl.Text = txt
    End If
End Sub

现在您可以看到我已将代码注释掉'WORKS',因为它确实存在,但我很困惑,因为委托MyDel.Invoke(lbl, txt)时,它会进入无限循环,因为委托是在主要形式声明。

谢谢。

编辑:为了澄清,主表单声明中的代表是:

Dim MyDel As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)

1 个答案:

答案 0 :(得分:4)

当你这样称呼时:

Private Sub SetLabelText_ThreadSafe(ByVal lbl As Label, ByVal txt As String)
    If lbl.InvokeRequired Then
        MyDel.Invoke(lbl, txt)

在后台主题上,发生了什么:

  • 使用BackgroundWorker
  • 在ThreadPool线程上运行此方法
  • 该方法调用lbl.InvokeRequiredTrue,因为这不是UI线程
  • 然后该方法调用执行委托的Delegate.Invoke。这有效地调用了方法
  • 该方法现在正在运行,但仍在非UI线程上,因此它立即看到lbl.InvokeRequired为真,并调用Delegate.Invoke - 创建无限循环

然而,当你致电Me.Invoke时,这有点不同。在此上下文中,Me是表单,因此您正在调用Control.Invoke,它将调用回调到UI线程。它然后运行,但是在那时,它将在UI线程上运行,因此lbl.InvokeRequired将是False,它将只运行一次而不是无限。