我正试图修补现有GUI中的问题,其中大部分是通过从这个答案粘贴到下面的代码解决的->如何等待BackgroundWorker取消?
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
// IS THERE ANY WAY TO TELL IF THE BACKGROUNDWORKER STOPPED DUE TO e.Cancel here???
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
while(!e.Cancel)
{
// do something
}
_resetEvent.Set(); // signal that worker is done
}
我的问题作为注释添加到Cancel函数的末尾。现在有没有办法知道为什么后台工作人员关闭了?
有很多选择。你可能可以检查CancellationPending
& help;我不记得当DoWork
处理程序返回—我对此表示怀疑,但如果是这样的话,你就会在等待和处理者之间进行一场赛跑。(我本来只是测试它自己,但你的问题不包括一个很好的最小,完整和可验证的代码示例,我没有麻烦自己创建一个。)
另一种方法是使用TaskCompletionSource<T>
代替AutoResetEvent
,它支持补全/取消语义:
private BackgroundWorker worker = new BackgroundWorker();
private TaskCompletionSource<object> _tcs;
public Form1()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
// Need to reinitialize when you actually start the worker...you
// didn't show that code, so I'm putting it here
_tcs = new TaskCompletionSource<object>();
}
public async Task Cancel()
{
worker.CancelAsync();
try
{
await _tcs.Task;
// you'll be here if the task completed normally
}
catch (TaskCancelledException)
{
// you'll be here if the task was cancelled
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
while(!e.CancellationPending)
{
// do something
}
if (e.CancellationPending)
{
_tcs.SetCanceled();
}
else
{
// if you actually want to return a value, you can set whatever
// value you want here. You can also use the correct type T for
// the TaskCompletionSource<T> declaration.
_tcs.SetResult(null);
}
}
如果你愿意,你可以把Cancel()
调用为Cancel().Wait()
,但如果你能在那里使用await
就更好了,这样你就可以避免阻塞线程。
比这更好的是从BackgroundWorker
切换到Task
和CancellationTokenSource
。然后,您等待的东西可以是任务本身,而不是任务的代理。