5

TPLとタスクについてサポートが必要です

これが私のシナリオです:

  1. タスクを生成するイベントハンドラーがいくつかあります。前のタスクが完了する前にイベントが呼び出された場合、続行する前にイベントを待機(ブロック)したいと思います。

  2. 呼び出されたときに、イベントハンドラーから生成されたタスクが完了するまで待機してから続行する必要がある同期メソッドがあります。


public void DoSomething()
{
    // Expects any running tasks from OnEvent1(), OnEvent2(), OnEvent3()
    // to be completed before proceeding.
}

public void OnEvent1()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

public void OnEvent2()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

public void OnEvent3()
{
    Task.Factory
    .StartNew(()=>{ /*Long running task*/ })
    .ContinueWith(task=>{ /* Updates UI */ });
}

実際のシナリオは次のようになります。

  • OnFetchData() =>タスクを生成します。これに対する後続のすべての呼び出しは、キューに入れる必要があります。
  • OnSyncSettings() =>タスクを生成します。これに対する後続のすべての呼び出しは、キューに入れる必要があります。

  • OnAutoBackup() =>同期メソッド。保存する前に、他のタスク(たとえば、データのフェッチ/同期設定)が完了するのを待ちます。

  • OnFullBackup() =>同期メソッド。FetchData()とSyncSettings()を手動で実行し、完了を待って続行します。

私の質問は単純です:どうすればこれを行うことができますか?

このアプローチは正しいでしょうか?

  1. 各イベントハンドラーは最後のを記憶しています。呼び出されると、リスト内のすべてのタスクが完了するのを待ってから続行します。

  2. 同期方式の場合、すべてのタスク(すべてのイベントハンドラーから)を待機する必要があります。


Task _lastEvent1Task;
public void OnEvent1()
{
    // Wait for all tasks to complete before proceeding
    if (_lastEvent1Task!=null)
    _lastEvent1Task.Clear();

    // Spawns new task
    _lastEvent1Task = Task.Factory.StartNew(()=>{ });
}

public void OnEvent3()
{
    // Wait for any running tasks to complete before proceeding
    if (_lastEvent1Task != null) _lastEvent1Task.Wait();
    if (_lastEvent2Task != null) _lastEvent2Task.Wait();
    ...
    // Proceed

}

ありがとう!


[編集]

DoSomething()が待機していて、Event1が発生した場合はどうなりますか?DoSomething()が実行されていて、イベントが発生した場合はどうなりますか?

OnEvents()

  • 最初のタスクの場合:タスクを生成し、非同期で実行します
  • 前のタスクがまだ実行中の場合は、キュー/ブロックします。クリティカルセクション。
  • 推定:
    • これらのイベントは通常、複数回発生することはありません。
    • UIは、ユーザーが実行中に同じイベントを発生させないようにすることが期待されています。

DoSomething()(呼び出された場合)

  • 想定:イベント通知は無効になっています。
  • 仮定:新しいイベントはキューに入れられません。
  • 予想:続行する前に、キューに入れられた残りのすべてのタスクが完了するまで待機します
  • 期待される:同期呼び出しであり、実行されるまで呼び出し元に戻らない
4

2 に答える 2

3

あなたが説明するアプローチには、並行性の問題があります。たとえば、のnullチェックの直後に、_lastEvent1Task他のスレッドが_lastEvent1Tasknullに設定され、。が発生する場合がありNullReferenceExceptionます。

すべてのタスクが同期して実行される必要があると想定していますが、一部のタスクはブロックされるべきではありません。これを実現する最良の方法は、単一のスレッドのみを使用するを使用することです。ここTaskSchedulerに例があります。

var scheduler = new SingleThreadedTaskScheduler();
var taskFactory = new TaskFactory(scheduler);

非ブロッキングメソッドの場合、次のようになります。

public void NonBlockingMethod()
{
    taskFactory
        .StartNew(() => { /* Long-running work. */ })
        .ContinueWith(t => { /* Update UI. */ });
}

あなたが得るブロッキング方法のために:

public void BlockingMethod()
{
    taskFactory
        .StartNew(() => { /* Do work. */ })
        .Wait();
}

タスクをスケジュールする場合、タスクスケジューラはタスクのスケジュールに1つのスレッドのみを使用し、すべてのタスクが同期して実行されることを保証します。

于 2012-10-09T14:31:54.350 に答える
0

ParExtSamplesのタスクスケジューラを使用する必要があると思います。通常、OnEvents()にOrderedTaskSchedulerが必要であり、スケジュールされたすべてのタスクがDoSomething()メソッドで完了するのを待つか、同じOrderedTaskSchedulerでDoSomething()メソッドをスケジュールすると、タスクがスケジュールされたときにのみ実行されます。その前に、完了します。

于 2012-10-10T14:12:14.857 に答える