如何在Form的Closing事件中停止BackgroundWorker?

THX*_*138 66 c# multithreading backgroundworker winforms

我有一个生成BackgroundWorker的表单,它应该更新表单自己的文本框(在主线程上),因此Invoke((Action) (...));调用.
如果HandleClosingEvent我只是做bgWorker.CancelAsync()然后我得到ObjectDisposedExceptionInvoke(...)电话,可以理解.但是,如果我坐在那里HandleClosingEvent等待bgWorker完成,那么.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
    }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 96

我知道唯一的死锁安全和异常安全的方法是实际取消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...
}
Run Code Online (Sandbox Code Playgroud)

  • 这有点危险,IsBusy是异步线程的属性.它可能会比赛.它实际上没有,但那是运气.此外,在RunWorkerCompleted触发之前,将重置CancellationPending. (8认同)
  • @lain:不,OnFormClosing和backgroundWorker1_RunWorkerCompleted都在UI线程上运行.一个人不能被另一个人打断. (7认同)
  • 一小段信息:您需要告诉BackGroundWorker实例可以取消它. (3认同)
  • 说到种族......如果工人在"if(!mCompleted)"之后正好完成正常工作,那么这不会失败吗? (2认同)