重用一个BackgroundWorker,取消并等待它 [英] Reusing a BackgroundWorker, cancel and wait for it

查看:241
本文介绍了重用一个BackgroundWorker,取消并等待它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设你有一个搜索文本框,并有连接到TextChanged事件搜索算法,与一个BackgroundWorker运行。如果在文本框中总会有一个新的角色,我需要取消以前的搜索,然后再次运行它。



我试图在主线程和BGW之间使用事件,从这个先前的问题,但我仍然得到错误现在忙,不能同时运行多个任务

  BackgroundWorker的bgw_Search =新的BackgroundWorker(); 
bgw_Search.DoWork + =新DoWorkEventHandler(bgw_Search_DoWork);

私人的AutoResetEvent _resetEvent =新的AutoResetEvent(假);

私人无效txtSearch_TextChanged(对象发件人,EventArgs五)
{
SearchWithBgw();
}

私人无效SearchWithBgw()
{
//取消以前的搜索
如果(bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();

//等待BGW完成,所以可以重复使用。
_resetEvent.WaitOne(); //将阻塞,直到_resetEvent.Set()调用取得
}

//启动新的搜索
bgw_Search.RunWorkerAsync(); //错误无法运行多个任务同时
}

无效bgw_Search_DoWork(对象发件人,DoWorkEventArgs E)
{
搜索(txtSearch.Text,E);
}

私人无效搜索(字符串aQuery,DoWorkEventArgs E)
{
INT I = 1;
,而(我3;)//模拟搜索处理...
{
Thread.sleep代码(1000);
I ++;

如果(bgw_Search.CancellationPending)
{
_resetEvent.Set(); //信号,即工人做
e.Cancel = TRUE;
的回报;
}
}
}



编辑以反映答案。鸵鸟政策重用的BackgroundWorker,创建一个新的:

 私人无效SearchWithBgw()
{
如果(bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); //将阻塞,直到_resetEvent.Set()调用取得

bgw_Search =新的BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = TRUE;
bgw_Search.DoWork + =新DoWorkEventHandler(bgw_Search_DoWork);
}

bgw_Search.RunWorkerAsync();
}


解决方案

在该_resetEvent.WaitOne( )调用完成,工作线程实际上并没有完成。这是从繁忙的DoWork(返回),并伺机运行RunWorkerCompleted事件(如有)。这需要时间。



有是确保对BGW没有可靠的方法以同步方式被完成。阻塞IsBusy或等待RunWorkerCompleted事件运行将会导致死锁。如果你的真正的希望只使用一个BGW那么你就必须要排队的请求。或者只是不出汗的小东西,另一个分配BGW。他们的成本的非常的一点。


Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.

I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"

    BackgroundWorker bgw_Search = new BackgroundWorker();
    bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);

    private AutoResetEvent _resetEvent = new AutoResetEvent(false);

    private void txtSearch_TextChanged(object sender, EventArgs e)
    {
        SearchWithBgw();
    }

    private void SearchWithBgw()
    {
        // cancel previous search
        if (bgw_Search.IsBusy)
        {
            bgw_Search.CancelAsync();

            // wait for the bgw to finish, so it can be reused.
            _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
        }

        // start new search
        bgw_Search.RunWorkerAsync();   // error "cannot run multiple tasks concurrently"
    }

    void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
    {
        Search(txtSearch.Text, e);
    }

    private void Search(string aQuery, DoWorkEventArgs e)
    {
        int i = 1;            
        while (i < 3)             // simulating search processing...
        {
            Thread.Sleep(1000);                           
            i++;

            if (bgw_Search.CancellationPending)
            {
                _resetEvent.Set(); // signal that worker is done
                e.Cancel = true;
                return;
            }
        }
    }

EDIT To reflect answers. Don´t reuse the BackgroundWorker, create a new one:

    private void SearchWithBgw()
    {   
        if (bgw_Search.IsBusy)
        {
            bgw_Search.CancelAsync();
            _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made

            bgw_Search = new BackgroundWorker();
            bgw_Search.WorkerSupportsCancellation = true;
            bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
        }

        bgw_Search.RunWorkerAsync();        
    }

解决方案

When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.

There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.

这篇关于重用一个BackgroundWorker,取消并等待它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆