为了账号安全,请及时绑定邮箱和手机立即绑定

如何等待BackgroundWorker取消?

如何等待BackgroundWorker取消?

C#
不负相思意 2019-10-25 14:53:32
考虑一个为您做事的对象的假设方法: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);这是不是它,那是不是我在做什么,那就是没有什么被要求在这里。如果真是这样,那么使用后台工作人员将毫无意义。
查看完整描述

3 回答

?
元芳怎么了

TA贡献1798条经验 获得超7个赞

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


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

}


查看完整回答
反对 回复 2019-10-25
?
UYOU

TA贡献1878条经验 获得超4个赞

此响应有问题。UI需要在您等待时继续处理消息,否则它将不会重新绘制,如果后台工作人员花很长时间来响应取消请求,这将是一个问题。


第二个缺陷是,_resetEvent.Set()如果工作线程引发异常-将使主线程无限期地等待-将永远不会被调用-但是,可以使用try / finally块轻松修复此缺陷。


一种方法是显示一个模态对话框,其中包含一个计时器,该计时器可反复检查后台工作人员是否已完成工作(或在您的情况下完成取消)。后台工作人员完成操作后,模态对话框将控制权返回给您的应用程序。在这种情况发生之前,用户无法与UI进行交互。


另一种方法(假设您最多打开一个无模式窗口)是设置ActiveForm.Enabled = false,然后在Application,DoEvents上循环,直到后台工作程序完成取消为止,然后可以再次设置ActiveForm.Enabled = true。


查看完整回答
反对 回复 2019-10-25
?
翻过高山走不出你

TA贡献1875条经验 获得超3个赞

几乎所有人都对这个问题感到困惑,并且不了解如何使用工人。


考虑一个RunWorkerComplete事件处理程序:


private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

{

    if (!e.Cancelled)

    {

        rocketOnPad = false;

        label1.Text = "Rocket launch complete.";

    }

    else

    {

        rocketOnPad = true;

        label1.Text = "Rocket launch aborted.";

    }

    worker = null;

}

一切都很好。


现在出现了这样一种情况,即呼叫者需要中止倒计时,因为他们需要执行火箭的紧急自毁。


private void BlowUpRocket()

{

    if (worker != null)

    {

        worker.CancelAsync();

        WaitForWorkerToFinish(worker);

        worker = null;

    }


    StartClaxon();

    SelfDestruct();

}

还有一种情况,我们需要打开火箭的检修门,而不是在倒计时时:


private void OpenAccessGates()

{

    if (worker != null)

    {

        worker.CancelAsync();

        WaitForWorkerToFinish(worker);

        worker = null;

    }


    if (!rocketOnPad)

        DisengageAllGateLatches();

}

最后,我们需要给火箭加油,但是在倒数计时中这是不允许的:


private void DrainRocket()

{

    if (worker != null)

    {

        worker.CancelAsync();

        WaitForWorkerToFinish(worker);

        worker = null;

    }


    if (rocketOnPad)

        OpenFuelValves();

}

没有等待工人取消的能力,我们必须将所有三个方法移至RunWorkerCompletedEvent:


private void OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

{

    if (!e.Cancelled)

    {

        rocketOnPad = false;

        label1.Text = "Rocket launch complete.";

    }

    else

    {

        rocketOnPad = true;

        label1.Text = "Rocket launch aborted.";

    }

    worker = null;


    if (delayedBlowUpRocket)

        BlowUpRocket();

    else if (delayedOpenAccessGates)

        OpenAccessGates();

    else if (delayedDrainRocket)

        DrainRocket();

}


private void BlowUpRocket()

{

    if (worker != null)

    {

        delayedBlowUpRocket = true;

        worker.CancelAsync();

        return;

    }


    StartClaxon();

    SelfDestruct();

}


private void OpenAccessGates()

{

    if (worker != null)

    {

        delayedOpenAccessGates = true;

        worker.CancelAsync();

        return;

    }


    if (!rocketOnPad)

        DisengageAllGateLatches();

}


private void DrainRocket()

{

    if (worker != null)

    {

        delayedDrainRocket = true;

        worker.CancelAsync();

        return;

    }


    if (rocketOnPad)

        OpenFuelValves();

}

现在,我可以这样编写代码,但是我不会。我不在乎,我只是不在乎。


查看完整回答
反对 回复 2019-10-25
  • 3 回答
  • 0 关注
  • 454 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信