无限循环和交叉线程

发布于 2024-11-16 14:41:01 字数 1522 浏览 4 评论 0原文

我是一名试图自学VB.NET的学生。今天我想解决BackgroundWorker 组件。我在网上找到了一篇很棒的文章: 如何使用后台工作者。我成功地完成了演练,甚至执行了“冒险”部分,该部分涉及使用委托跨线程更新控件。

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

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

    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)

I am a student attempting to learn VB.NET on my own. Today I wanted to tackle the BackgroundWorker component. I found an excellent article online: How To Use a Background Worker. I successfully completed the walkthrough and even performed the "adventorous" part that dealt with working with controls updating across threads using delegates.

Now I came to a part that I didn't understand how it was working. To summarize the following code, I have a delegate that has a Label and a String in its signature. I then have a subroutine that is called on the worker thread. Inside this subroutine the delegate is created and (I guess) ran again so that it is on the same (Main) thread. Please correct me if I'm wrong here.

Here is the method is performed on the worker thread:

    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

I've only included the line of code that is of importance to this question. As you can see this then calls a subroutine that I mentioned:

    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

Now as you can see I have the code commented out 'WORKS' because it does, but I'm confused as why it goes into an infinite loop when the MyDel.Invoke(lbl, txt) is called because the delegate is created in the Main form Declarations.

Thank you.

EDIT: And for clarification, the delegate in the Main form Declaractions is:

Dim MyDel As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

×纯※雪 2024-11-23 14:41:01

当您调用此方法时:

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

在后台线程上,发生的情况是这样的:

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

但是,当您调用 Me.Invoke 时,情况有点不同。在这种情况下,Me 是表单,因此您正在调用 Control.Invoke,它将回调编组回 UI 线程。然后它会运行,但此时它将在 UI 线程上运行,因此 lbl.InvokeRequired 将为 False,并且它只会运行一次而不是去无限。

When you call this:

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

On a background thread, what's happening is this:

  • You run this method on a ThreadPool thread by using BackgroundWorker
  • The method calls lbl.InvokeRequired, which is True, since this is not the UI thread
  • The method then calls Delegate.Invoke, which executes the delegate. This effectively calls the method
  • The method is now running, but still on a non-UI thread, so it immediately sees lbl.InvokeRequired is true, and calls Delegate.Invoke - creating the infinite loop

However, when you call Me.Invoke, this is a bit different. Me, in this context, is the Form, so you're calling Control.Invoke, which marshals the call back to the UI thread. It then runs, but at that point, it'll be running on the UI thread, so lbl.InvokeRequired will be False, and it'll just run once and not go infinite.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文