在backgroundworker
内进行长时间运行的测量。由于SRP
(Single reponsibility principle),衡量应该不知道它正在另一个线程中运行。
让我们考虑一下这个例子:
void MeasurementWorker(object sender, DoWorkEventArgs e)
{
Measurement measurement = new Measurement();
measurement.Execute();
}
如何取消测量这样的模式?
编辑:Measurement.Execute
现在是长期运行的测量方法,该方法应该是可取消的,但是应该使用线程上下文来违反测量的SRP
。例如,在没有线程上下文的情况下进行一些测试。
答案 0 :(得分:2)
就像我在评论中说的那样,我会使用TPL来解决这个问题。这是一个允许在不违反SRP的情况下取消的解决方案:
将.NET Framework BackgroundWorker包装在您自己的类中,实现和接口ICancellable如下:
public interface ICancellable
{
bool CancellationPending {get;}
}
public class BackgroundWorkerWrapper : ICancellable
{
private BackgroundWorker _realWorker;
public BackgroundWorkerWrapper(BackgroundWorker realWorker)
{
_realWorker = realWorker;
}
public bool CancellationPending
{
get { return _realWorker.CancellationPending; }
}
}
在DoWork处理程序中,执行以下操作:
void MeasurementWorker(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ICancellable cancellable = new BackgroundWorkerWrapper(worker);
Measurement lastMeasurement = new Measurement();
lastMeasurement.Execute(cancellable);
}
现在,在您的测量中,您可以使用CancellationPending属性检查是否以干净的方式请求取消。
你说什么?
答案 1 :(得分:2)
如果您希望您的测量处理可以取消,您必须让它知道某种取消标记。另一种方法是以不合规的方式取消它(中止),但这是非常气馁的,因为你可以在重要的事情中停止处理,而不给它机会清理或释放资源。
而不是BackgroundWorker
您可以使用Task Parallel Library,然后代码可能如下所示:
CancellationTokenSource cts = new CancellationTokenSource();
Task tsk = Task.Factory.StartNew(() =>
{
Measurement measurement = new Measurement();
measurement.Execute(cts.Token);
},
cts.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
其中Execute
可能如下所示:
public void Execute(CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
while (true)
{
// processing
// ...
// need to cancel?
ct.ThrowIfCancellationRequested();
}
}
要取消在主线程中调用它:
cts.Cancel();
您将获得TaskCancelledException
,但这是预期的。
或者,如果您不想要例外,请使用以下版本的Execute
。它并非严格按照TPL指南,但如果您不使用条件continuations,它将正常工作。
public void Execute(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return;
while (true)
{
// processing
if (ct.IsCancellationRequested)
return;
}
}