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,但这听起来不是很优雅.有没有更简单的方法?
是的,这里有一场比赛.在目标开始运行之前,A需要很长的时间.如果使用Control.BeginInvoke(),它将更好地工作,表单的Dispose()实现将清空调度队列.但这仍然是一场比赛,尽管很少会发生.您在代码段中编写的代码不需要Invoke().
唯一干净的解决方法是将FormClosing事件联锁并延迟关闭,直到您确认后台线程已完成且无法再次启动.您的代码不容易,因为这需要"完成"回调,因此您可以真正关闭表单. BackgroundWorker将是一个更好的捕鼠器.Q&D修复是捕获BeginInvoke将引发的ObjectDisposedException.鉴于使用BeginInvoke()时这种情况有多么罕见,这种丑陋的黑客行为是可以接受的.你就是无法测试它:)