一尘不染

如何等待BackgroundWorker取消?

c#

考虑一个为您 做事 的对象的 假设 方法:

public class DoesStuff
{
    BackgroundWorker _worker = new BackgroundWorker();

    ...

    public void CancelDoingStuff()
    {
        _worker.CancelAsync();

        //todo: Figure out a way to wait for BackgroundWorker to be cancelled.
    }
}

一个人如何等待BackgroundWorker完成?


过去人们尝试过:

while (_worker.IsBusy)
{
    Sleep(100);
}

但是,此死锁IsBusy是因为直到RunWorkerCompleted事件被处理后才被清除,并且该事件只有在应用程序变得空闲之后才能得到处理。直到工作人员完成后,应用程序才会处于空闲状态。(此外,这是一个繁忙的循环-
令人作呕。)

其他人则建议将其合并为:

while (_worker.IsBusy)
{
    Application.DoEvents();
}

这样做的问题是Application.DoEvents()导致当前队列中的消息被处理,从而导致重新输入问题(.NET不能重新输入)。

我希望使用一些涉及事件同步对象的解决方案,其中代码 等待 事件-工作者的RunWorkerCompleted事件处理程序设置的事件。就像是:

Event _workerDoneEvent = new WaitHandle();

public void CancelDoingStuff()
{
    _worker.CancelAsync();
    _workerDoneEvent.WaitOne();
}

private void RunWorkerCompletedEventHandler(sender object, RunWorkerCompletedEventArgs e)
{
    _workerDoneEvent.SetEvent();
}

但是我又回到了僵局:事件处理程序要等到应用程序空闲后才能运行,并且应用程序也不会因为等待事件而空闲。

那么,如何等待BackgroundWorker完成呢?


更新 人们似乎对此问题感到困惑。他们似乎认为我将使用BackgroundWorker作为:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyWork;
worker.RunWorkerAsync();
WaitForWorkerToFinish(worker);

这是 不是 它,那是 不是 我在做什么,那就是 没有 什么被要求在这里。如果真是这样,那么使用后台工作人员将毫无意义。


阅读 208

收藏
2020-05-19

共1个答案

一尘不染

如果我了解您的要求正确,则可以执行以下操作(代码未经测试,但显示了总体思路):

private BackgroundWorker worker = new BackgroundWorker();
private AutoResetEvent _resetEvent = new AutoResetEvent(false);

public Form1()
{
    InitializeComponent();

    worker.DoWork += worker_DoWork;
}

public void Cancel()
{
    worker.CancelAsync();
    _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!e.Cancel)
    {
        // do something
    }

    _resetEvent.Set(); // signal that worker is done
}
2020-05-19