BackgroundWorker
艺术品收藏中有DoWork
来制作和ParallelForeach
处理。
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int cnt = (int) e.Argument;
List<int[]> ListArrays = new List<int[]>();
for (int i=0; i<cnt ; i++)
{
Random rnd = new Random((int)DateTime.Now.Ticks);
int length = rnd.Next(5000, 100000);
ListArrays.Add(new int[length]);
for (int j = 0; j < ListArrays[i].Length; j++)
{
ListArrays[i][j] = rnd.Next(0, 1000000);
}
}
int progress=0;
Parallel.ForEach(ListArrays, item =>
{
if (_backgroundWorker != null)
{
if (_backgroundWorker.WorkerReportsProgress)
{
_backgroundWorker.ReportProgress((int)(progress / (cnt / 100M)));
}
if (_stopThread)
{
_busy.WaitOne();
}
if (_backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
Worker worker = new Worker();
worker.FindPrimes(item);
CounterPrimes += worker.CounterPrimes;
progress++;
}
});
}
有按钮&#34;停止&#34;,&#34;暂停&#34;和&#34;恢复&#34;。在启动停止后正常工作。但如果你采取&#34;暂停&#34;然后在停止按钮不起作用后继续,为什么?
AutoResetEvent _busy = new AutoResetEvent(false);
bool _stopThread;
private void StopBtn_OnClick(object sender, RoutedEventArgs e)
{
// _stopThread = false;
//_busy.Set();
_backgroundWorker.CancelAsync();
}
private void PauseBtn_OnClick(object sender, RoutedEventArgs e)
{
PauseBtn.IsEnabled = false;
_stopThread = true;
ResumeBtn.IsEnabled = true;
}
private void ResumeBtn_OnClick(object sender, RoutedEventArgs e)
{
ResumeBtn.IsEnabled = false;
PauseBtn.IsEnabled = true;
_stopThread = false;
_busy.Set();
}
答案 0 :(得分:1)
当您致电_backgroundWorker.CancelAsync()
时,它会将CancellationPending
标记为true,但您的代码有责任定期检查CancellationPending
是否已标记并停止运行。
在您的代码中,您会检查CancellationPending
,但您最初只会检查一次。大部分工作都是在Worker
课程中完成的,但它只在你检查后执行,这就是为什么它只能在一开始就工作(无论你是否点击了暂停)。
出于同样的原因,您的暂停功能也只能在最开始工作,因为您只检查一次_stopThread
标志。
作为示例解决方案,您可以将检查暂停和停止的代码移动到单独的方法:
private bool shouldStopWork(DoWorkEventArgs e)
{
_busy.WaitOne();
if (_backgroundWorker.CancellationPending)
{
e.Cancel = true;
return true;
}
return false;
}
您可以为此创建Func
以封装事件参数Func<bool> shouldStop = () => shouldStopWork(e);
,然后将此Func
传递给其构造函数中的Worker
类,然后使用Worker
类在其FindPrimes
方法中定期调用它,并在需要时退出该方法。
你遇到的另一个问题是你正在使用AutoResetEvent
这意味着如果你暂停然后恢复,只有一个工作人员会醒来,这不是你想要的。您希望所有工作人员都醒着,因此您需要使用ManualResetEvent
。另请注意,我删除了_stopThread
标志的使用,因为重置事件中已经有一个标记,所以不需要它,尽管您需要在暂停点击的事件中重置事件:_busy.Reset();
最后一点:就像@Panagiotis Kanavos提到的那样,BackgroundWorker
是旧的做事方式,你可以使用async / await,tasks和Progress
类来报告进度(例如:{{ 3}}),但请注意,这并不能免除您定期检查Worker
课程中需要取消的责任。这样做的原因是,在没有“另一方”帮助的情况下实现取消的唯一方法是猛烈地杀死线程,但这可能使应用程序处于未确定状态。这就是为什么Thread.Abort
也被弃用的原因。