Бесконечный цикл и поперечная резьба - PullRequest
3 голосов
/ 22 июня 2011

Я студент, пытающийся изучать 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

Теперь, как вы можете видеть, у меня есть закомментированный код «РАБОТАЕТ», потому что он делает, но я запутался, почему он входит в бесконечный цикл при вызове MyDel.Invoke(lbl, txt), потому что делегат создается в форме Main Объявления.

Спасибо.

РЕДАКТИРОВАТЬ: И для пояснения, делегат в основной форме декларации:

Dim MyDel As New SetLabelText_Delegate(AddressOf SetLabelText_ThreadSafe)

1 Ответ

4 голосов
/ 22 июня 2011

Когда вы вызываете это:

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

В фоновом потоке происходит следующее:

  • Этот метод запускается в потоке ThreadPool с помощью BackgroundWorker
  • Метод вызывает lbl.InvokeRequired, то есть True, поскольку это не поток пользовательского интерфейса
  • Затем метод вызывает Delegate.Invoke, который выполняет делегат.Это фактически вызывает метод
  • Метод теперь запущен, но все еще в потоке, не являющемся пользовательским интерфейсом, поэтому он сразу видит, что lbl.InvokeRequired имеет значение true, и вызывает Delegate.Invoke - создание бесконечного цикла

Однако, когда вы звоните Me.Invoke, это немного по-другому.Me, в данном контексте, это форма, поэтому вы звоните Control.Invoke, которая маршализирует обратный вызов в поток пользовательского интерфейса.Затем он запускается, но в этот момент он будет работать в потоке пользовательского интерфейса, поэтому lbl.InvokeRequired будет False, и он просто запустится один раз и не будет бесконечным.

...