1

内で長時間測定を行うbackgroundworker。測定は、 (単一責任の原則) のため、別のスレッドで実行されていることを認識してはなりませんSRP

たとえば、次のように考えてみましょう。

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

このようなパターンの測定のキャンセルを許可するにはどうすればよいですか?

編集:Measurement.Executeキャンセル可能であるはずの長時間実行される測定方法になりましたSRPが、測定がスレッド化コンテキストに違反してはなりません。たとえば、スレッド化コンテキストなしでテストを行う場合などです。

4

2 に答える 2

2

コメントで述べたように、この問題には TPL を使用します。SRP に違反せずにキャンセルできるソリューションを次に示します。

次のように、ICancellable を実装およびインターフェイスする独自のクラスに .NET Framework Ba​​ckgroundWorker をラップします。

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

測定処理をキャンセル可能にしたい場合は、ある種のキャンセルフラグを認識させる必要があります。別の方法として、非準拠の方法でキャンセル (中止) することもできますが、リソースをクリーンアップまたは解放する機会を与えずに、重要なことの途中で処理を停止する可能性があるため、これはお勧めできません。

代わりにTask Parallel LibraryBackgroundWorkerを使用すると、コードは次のようになります。

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 に答える