首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在窗体的关闭事件上停止BackgroundWorker?

如何在窗体的关闭事件上停止BackgroundWorker?
EN

Stack Overflow用户
提问于 2009-11-14 03:32:31
回答 11查看 51.7K关注 0票数 73

我有一个窗体,它产生一个BackgroundWorker,它应该更新窗体自己的文本框(在主线程上),因此调用Invoke((Action) (...));

如果在HandleClosingEvent中我只做bgWorker.CancelAsync(),那么我在Invoke(...)调用上得到ObjectDisposedException,这是可以理解的。但是如果我坐在HandleClosingEvent中等待bgWorker完成,那么.Invoke(...)再也不回来了,这也是可以理解的。

你知道如何在不出现异常或死锁的情况下关闭这个应用吗?

下面是简单Form1类的3个相关方法:

代码语言:javascript
复制
    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
    }
EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2009-11-14 06:41:03

据我所知,要做到这一点,唯一的死锁安全和异常安全方法是实际取消FormClosing事件。如果BGW仍在运行,则设置e.Cancel = true,并设置一个标志以指示用户请求关闭。然后在BGW的RunWorkerCompleted事件处理程序中检查该标志,如果设置了该标志,则调用Close()。

代码语言:javascript
复制
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...
}
票数 102
EN

Stack Overflow用户

发布于 2010-08-12 23:20:26

这是我的解决方案(很抱歉,它是用VB.Net编写的)。

当我运行FormClosing事件时,我运行FormClosing Worker1.CancelAsync()将FormClosing()值设置为True。不幸的是,该程序从未真正有机会检查CancellationPending值以将e.Cancel设置为true (据我所知,这只能在BackgroundWorker1_DoWork中完成)。我没有删除这一行,尽管它看起来并没有真正的不同。

我添加了一行代码,将我的全局变量bClosingForm设置为True。然后,我在BackgroundWorker_WorkCompleted中添加了一行代码,以便在执行任何结束步骤之前检查e.Cancelled和全局变量bClosingForm。

使用此模板,您应该能够随时关闭表单,即使后台工作人员正在处理某些事情(这可能不太好,但它肯定会发生,所以最好还是处理它)。我不确定是否有必要,但在这一切发生后,您可以在Form_Closed事件中完全处理后台工作程序。

代码语言:javascript
复制
Private bClosingForm As Boolean = False

Private Sub SomeFormName_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    bClosingForm = True
    BackgroundWorker1.CancelAsync() 
End Sub

Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    'Run background tasks:
    If BackgroundWorker1.CancellationPending Then
        e.Cancel = True
    Else
        'Background work here
    End If
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    If Not bClosingForm Then
        If Not e.Cancelled Then
            'Completion Work here
        End If
    End If
End Sub
票数 2
EN

Stack Overflow用户

发布于 2012-03-09 18:55:02

我找到了另一种方法。如果你有更多的backgroundWorkers,你可以:

代码语言:javascript
复制
List<Thread> bgWorkersThreads  = new List<Thread>();

在每一个背景下,DoWork的DoWork方法都会使:

代码语言:javascript
复制
bgWorkesThreads.Add(Thread.CurrentThread);

您可以使用以下几个选项:

代码语言:javascript
复制
foreach (Thread thread in this.bgWorkersThreads) 
{
     thread.Abort();    
}

我在控制中的Word Add-in中使用了它,我在CustomTaskPane中使用它。如果有人在所有backgroundWorkes完成工作之前就关闭了文档或应用程序,就会引发一些COM Exception(我已经记不清是哪一个了)。CancelAsync()不能工作。

但是有了这个,我可以在DocumentBeforeClose事件中立即关闭backgroundworkers使用的所有线程,我的问题就解决了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1731384

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档