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

时间:2016-06-13 18:42:05

标签: vb.net multithreading winforms formclosing

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

一旦将sentinel值设置为true(由另一个处理Me.FormClosing的方法设置),for循环将退出

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

ObjectDisposedExceptionComponentModel.Win32Exception

如果没有"吃"我如何正确退出表格?这些例外并忽略它们。

代码:

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

2 个答案:

答案 0 :(得分:1)

错误来自哪里?

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

  1. 用户(或其他)关闭表单。
  2. 然后调用
  3. FormClosing_exit设置为True
  4. 然后表格自行关闭,摧毁它的手柄。
  5. 现在,它取决于它有时会抛出异常:
    • 线程刚刚完成Invoke或Loop,检查_exit值然后结束循环,一切顺利。
    • 要么它刚刚开始调用,那么它调用一个调用UI线程的方法来修改刚处理过的表单上的内容,不再处理这个表单,导致ObjectDisposedException
  6. 如何防止这种情况?

    您可以做的一件事是,在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
    

答案 1 :(得分:0)

我不熟悉VB,但我在c ++中做过类似的事情。主要问题是当窗体关闭时for循环还没有完成。您可以隐藏表单,等待线程完成然后关闭表单。您可以使用标记来标记停止并列线程。