1

backgroundworker. 由于(单一责任原则),测量不应该知道它正在另一个线程中运行。SRP

让我们考虑一下这个例子:

void MeasurementWorker(object sender, DoWorkEventArgs e)
{
   Measurement measurement = new Measurement();
   measurement.Execute();
}

如何允许取消测量这样的模式?

编辑:Measurement.Execute现在是长期运行的测量方法,它应该是可以取消的,但它不SRP应该与线程上下文相冲突。例如在没有线程上下文的情况下进行一些测试。

4

2 回答 2

2

就像我在评论中所说的那样,我会使用 TPL 来解决这个问题。这是一个在不违反 SRP 的情况下允许取消的解决方案:

将 .NET Framework Ba​​ckgroundWorker 包装在您自己的实现和接口 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 属性检查是否以干净的方式请求取消。

你说的话?

于 2013-04-13T19:58:27.937 回答
2

如果你希望你的测量处理是可取消的,你必须让它知道某种取消标志。另一种方法是以不合规的方式取消它(中止),但这是非常不鼓励的,因为您可能会在重要的事情中间停止处理,而没有机会清理或释放资源。

而不是BackgroundWorker您可以使用任务并行库,然后代码可能如下所示:

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 指南,但如果您不使用条件延续,它会正常工作。

public void Execute(CancellationToken ct)
{
    if (ct.IsCancellationRequested)
        return;

    while (true)
    {
        // processing
        if (ct.IsCancellationRequested)
            return;
    }
}
于 2013-04-14T19:31:47.003 回答