C#- 后台工作人员的 CancelAsync() 不起作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18314873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C#- background worker's CancelAsync() not working?
提问by Neel Bhasin
I want to abort the process but not able to do so, I am using Background worker with my functions of processing.
我想中止该过程但无法这样做,我正在使用具有处理功能的后台工作人员。
public void Init()
{
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
if (bw.CancellationPending == true)
{
e.Cancel = true;
}
else
{
e.Result = abd();
}
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled)
{
lbltext.content="Canceled";
}
else
{
lbltext.content="Completed";
}
}
private void btncan_Click(object sender, RoutedEventArgs e)
{
bw.CancelAsync();
}
private void btnstart_Click(object sender, RoutedEventArgs e)
{
bw.RunWorkerAsync();
}
I am not able to abort the process using this code.
Function abd()
is performing the processing part and returning the result.
我无法使用此代码中止该过程。函数abd()
正在执行处理部分并返回结果。
Please provide me any solution.
请为我提供任何解决方案。
Thanks.
谢谢。
回答by Sergey Berezovskiy
When you call bw.CancelAsync()
you just set CancellationPending
flag to true
. It does not cancels something by default. You need to handle pending cancellation manually. But you can't do that with your code, because when you click button, there are three possible options:
当您打电话时,bw.CancelAsync()
您只需将CancellationPending
标志设置为true
. 默认情况下它不会取消某些内容。您需要手动处理挂起的取消。但是你不能用你的代码来做到这一点,因为当你点击按钮时,有三个可能的选项:
- Long-running
abd()
method finished it's work and there is nothing to cancel abd()
started it's work, and background worker is blocked - it's waiting for results ofabd()
, then it continues execution - i.e. exitsif-else
block and raisesRunWorkerCompleted
event.- Nearly impossible option - you will be fast as light, and you will click button before
if-else
block entered. ThanCancellationPending
will be true, andabd()
will not start execution
- 长时间运行的
abd()
方法完成了它的工作,没有什么可以取消的 abd()
开始它的工作,后台工作程序被阻止 - 它正在等待 的结果abd()
,然后它继续执行 - 即退出if-else
阻止并引发RunWorkerCompleted
事件。- 几乎不可能的选项 - 你会像光一样快,你会在
if-else
进入块之前点击按钮。比CancellationPending
将是真的,并且abd()
不会开始执行
If you want to use cancellation, then do your long-running task in a loop, and check if cancellation is pending on each step:
如果要使用取消,请在循环中执行长时间运行的任务,并检查每个步骤是否有待取消:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
List<Foo> results = new List<Foo>();
// any loop here - foreach, while
for(int i = 0; i < steps_count; i++)
{
// check status on each step
if (bw.CancellationPending == true)
{
e.Cancel = true;
return; // abort work, if it's cancelled
}
results.Add(abd()); // add part of results
}
e.Result = results; // return all results
}
回答by Anirudha
Probably DoWork
may have finished its work before calling CancelAsync
and as mentioned in the docs e.Cancelled
may be false..
可能DoWork
在调用之前已经完成了它的工作,CancelAsync
并且正如文档中提到的那样e.Cancelled
可能是错误的..
Docssay this
文档这样说
Be aware that your code in the DoWork event handler may finish its work as a cancellation request is being made, and your polling loop may miss CancellationPending being set to true. In this case, the Cancelled flag of System.ComponentModel.RunWorkerCompletedEventArgs in your RunWorkerCompleted event handler will not be set to true, even though a cancellation request was made. This situation is called a race condition and is a common concern in multithreaded programming.
请注意,DoWork 事件处理程序中的代码可能会在发出取消请求时完成其工作,并且您的轮询循环可能会错过将 CancellationPending 设置为 true 的情况。在这种情况下,即使发出取消请求,RunWorkerCompleted 事件处理程序中 System.ComponentModel.RunWorkerCompletedEventArgs 的 Canceled 标志也不会设置为 true。这种情况称为竞争条件,是多线程编程中常见的问题。
回答by Anirudha
How about the following?
以下情况如何?
While(!bw.CancellationPending)
{
//do some work!
}
e.Cancel = true;
回答by Suryanshu Singh
Looks like function abd()
take too much processing time and you want to Abort it in between.
看起来函数abd()
需要太多处理时间,您想在两者之间中止它。
private Thread _backgroundWorkerThread;
public void AbortBackgroundWorker()
{
if(_backgroundWorkerThread != null)
_backgroundWorkerThread.Abort();
}
void DoWork(object sender, DoWorkEventArgs e)
{
try
{
_backgroundWorkerThread = Thread.CurrentThread;
// call abd...
}
catch(ThreadAbortException)
{
// Do your clean up here.
}
}
Put AbortBackgroundWorker()
in btncan_Click
event.
But this comes with a cost. Now the RunWorkerCompleted event will not work. So, you will have to handle it in catch block or write some code of our own.
将AbortBackgroundWorker()
在btncan_Click
事件。但这需要付出代价。现在 RunWorkerCompleted 事件将不起作用。因此,您必须在 catch 块中处理它或编写一些我们自己的代码。