C#Winforms线程:调用Closed Form

dri*_*ter 5 c# invoke thread-safety winforms

以下代码说明了我的困境.代码创建一个处理内容的后台线程,然后使用结果调用UI线程.

如果后台线程在窗体关闭后调用窗体上的Invoke,它可能会抛出异常.它在调用Invoke之前检查IsHandleCreated,但是在检查之后表单可能会关闭.

void MyMethod()
{
    // Define background thread
    Action action = new Action(
        () =>
        {
            // Process something
            var data = BackgroundProcess();

            // Try to ensure the form still exists and hope
            // that doesn't change before Invoke is called
            if (!IsHandleCreated)
                return;

            // Send data to UI thread for processing
            Invoke(new MethodInvoker(
                () =>
                {
                    UpdateUI(data);
                }));
        });

    // Queue background thread for execution
    action.BeginInvoke();
}
Run Code Online (Sandbox Code Playgroud)

一种解决方案可能是同步FormClosing和每次调用Invoke,但这听起来不是很优雅.有没有更简单的方法?

Han*_*ant 5

是的,这里有一场比赛.在目标开始运行之前,A需要很长的时间.如果使用Control.BeginInvoke(),它将更好地工作,表单的Dispose()实现将清空调度队列.但这仍然是一场比赛,尽管很少会发生.您在代码段中编写的代码不需要Invoke().

唯一干净的解决方法是将FormClosing事件联锁并延迟关闭,直到您确认后台线程已完成且无法再次启动.您的代码不容易,因为这需要"完成"回调,因此您可以真正关闭表单. BackgroundWorker将是一个更好的捕鼠器.Q&D修复是捕获BeginInvoke将引发的ObjectDisposedException.鉴于使用BeginInvoke()时这种情况有多么罕见,这种丑陋的黑客行为是可以接受的.你就是无法测试它:)