我有一个生成BackgroundWorker的表单,该表单应该更新表单自己的文本框(在主线程上),因此进行Invoke((Action) (...));调用。 如果HandleClosingEvent我真bgWorker.CancelAsync()那么我得到ObjectDisposedException的Invoke(...)电话,可以理解。但是,如果我坐在那里HandleClosingEvent等待bgWorker完成,那么.Invoke(…)永远不会返回,这也是可以理解的。
Invoke((Action) (...));
HandleClosingEvent
bgWorker.CancelAsync()
ObjectDisposedException
Invoke(...)
有什么想法如何关闭该应用程序而不会出现异常或死锁吗?
以下是简单Form1类的3种相关方法:
public Form1() { InitializeComponent(); Closing += HandleClosingEvent; this.bgWorker.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { while (!this.bgWorker.CancellationPending) { Invoke((Action) (() => { this.textBox1.Text = Environment.TickCount.ToString(); })); } } private void HandleClosingEvent(object sender, CancelEventArgs e) { this.bgWorker.CancelAsync(); /////// while (this.bgWorker.CancellationPending) {} // deadlock }
我知道,唯一的无死锁和异常安全的方法是实际上取消FormClosing事件。如果BGW仍在运行,则设置e.Cancel = true,并设置一个标志以指示用户请求关闭。然后在BGW的RunWorkerCompleted事件处理程序中检查该标志,并设置Close()。
private bool closePending; protected override void OnFormClosing(FormClosingEventArgs e) { if (backgroundWorker1.IsBusy) { closePending = true; backgroundWorker1.CancelAsync(); e.Cancel = true; this.Enabled = false; // or this.Hide() return; } base.OnFormClosing(e); } void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (closePending) this.Close(); closePending = false; // etc... }