正确关闭表单 运行 新线程中的循环

Properly closing a form running a loop in a new thread

我的表单中有方法 运行 在新线程中执行 while 循环。

一旦标记值设置为 true(由另一个处理 Me.FormClosing 的方法设置)

,for 循环就会退出

问题是当表单关闭时,我偶尔会遇到两个异常。

ObjectDisposedExceptionComponentModel.Win32Exception.

如何在没有 "eating" 这些异常并忽略它们的情况下正确退出表单。

代码:

Dim _exit As Boolean

Public Sub test()
    Dim task As Thread = New Thread(
            Sub()
                Do
                    checkInvoke(Sub() a.append("a"))
                Loop While _exit = False
            End Sub)
End Sub

Private Sub checkInvoke(ByVal _call As Action)
    If Me.InvokeRequired Then
        Me.Invoke(Sub() checkInvoke(_call))
    Else
        _call.Invoke()
    End If
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    _exit = True
End Sub

我对VB不熟悉,但是我用c++做过类似的事情。主要问题是 for 循环在表单关闭时尚未完成。您可以只隐藏表单,等待线程完成,然后关闭表单。您可以使用标志来标记并行线程的停止。

错误从何而来?

这可能有点令人困惑,但实际上很合乎逻辑...

  1. 用户(或其他人)关闭了表单。
  2. 然后调用
  3. FormClosing_exit 设置为 True
  4. 然后窗体自行关闭,销毁其句柄。
  5. 现在,这取决于有时抛出异常的位置:
    • 线程刚刚完成调用或循环,检查 _exit 值然后结束循环,一切正常。
    • 要么是刚刚开始Invoke,然后调用了一个方法调用UI线程去修改刚刚处理掉的表单上的东西,不再Handle这个表单,导致ObjectDisposedException

如何预防?

您可以做的一件事是,在您的 FormClosing 事件中,等待线程结束,然后让系统关闭表单:

Private _isFinished As Boolean = False
Private _exit As Boolean = False

Public Sub test()
    Dim task As Thread = New Thread(
            Sub()
                Do
                    checkInvoke(Sub() a.append("a"))
                Loop While _exit = False
                'We inform the UI thread we are done
                _isFinished = True
            End Sub)
End Sub


Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    _exit = True
    While Not _isFinished
        Application.DoEvent() 'We can't block the UI thread as it will be invoked by our second thread...
    End While
End Sub