2

bool を返すタスクがいくつかあります。最初にタスクがTrueを返すまで待ち​​たいだけです。出来ますか ?

私の最初のアイデアは、CancellationTokenSource を使用することでしたが、Task.WaitAll メソッドを呼び出すと例外がスローされるため、お勧めできませんでした。

2 番目のオプションは、参照で渡す bool を使用し、それが true の場合は直接返すことです。動作しますが、パフォーマンスが高くありません:

bool isFound = false;
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(paramA, paramB, ref isFound));
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(paramC, paramD, ref isFound));
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(paramE, paramF, ref isFound));
Task<bool> t3 = Task.Factory.StartNew<bool>(() => Find(paramG, paramH, ref isFound));

Task.WaitAll(new Task[] { t0, t1, t2, t3, t4 });
return t0.Result | t1.Result | t2.Result | t3.Result | t4.Result;

そしてメソッドで:

 private static bool Find(int[,] m1, int[,] m2, ref bool isFound)
 {
      if (isFound)
           return false;

      // Do work...
 }

編集 :

答えが事前にわかっているので、私はTaskCompletionSource<bool>now を使用します:

TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(paramA, paramB);
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(paramC, paramD);
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(paramE, paramF);
Task<bool> t3 = Task.Factory.StartNew<bool>(() => Find(paramG, paramH);

t0.ContinueWith(_ =>
{
    if (t0.Result)
        tcs.TrySetResult(t0.Result);
});

t1.ContinueWith(_ =>
{
    if (t1.Result)
        tcs.TrySetResult(t1.Result);
});

t2.ContinueWith(_ =>
{
    if (t2.Result)
        tcs.TrySetResult(t2.Result);
});

t3.ContinueWith(_ =>
{
    if (t3.Result)
        tcs.TrySetResult(t3.Result);
});

t4.ContinueWith(_ =>
{
    if (t4.Result)
        tcs.TrySetResult(t4.Result);
});

tcs.Task.Wait();
return tcs.Task.Result;

この場合、すべてのタスクが false を返すと、何も気付かれず、正常です。ただし、メソッドの使用方法がわかりませんWhenAll。私はこれを追加しようとしました:

tcs.Task.Wait();
Task tr = Task.WhenAll(new Task[] { t0, t1, t2, t3, t4 });

if (tr.IsCompleted)
    return false;
else
    return tcs.Task.Result;

しかし、それは機能しません:(

4

3 に答える 3

6

1 つのオプションはTaskCompletionSource、任意のタイプの を作成することです (必要に応じて結果を識別するため)。次に、各タスクに継続を追加しTaskCompletionSource.TrySetResult、結果が true の場合に呼び出します。

あとは を待つだけTaskCompletionSource.Taskです。Task.WaitAny繰り返し電話をかけたり、結果を確認したりする必要がなくなります。

トリッキーなビットは、すべてのタスクが false を返したときに気付くことです... .NET 4.5 では、別のタスクを作成することにより、これはかなり簡単になります。その後、最初のタスクが完了するTask.WhenAllのを待つだけです。{ success, all failed }

于 2012-08-06T08:27:53.950 に答える
3

You need WaitHandle.WaitAny. At the very beginning you set up a WaitHandle[], each one waits a Task, when the task is successfully executed (and get true as a result as you expected), you signal the corresponding WaitHandle.

于 2012-08-06T08:26:43.570 に答える
1

プロパティを冗長にするManualResetEventを使用できます。isFound

private static ManualResetEvent found = new ManualResetEvent(false);
...

Task.Factory.StartNew<bool>(() => Find(paramA, paramB));     
Task.Factory.StartNew<bool>(() => Find(paramC, paramD));     
Task.Factory.StartNew<bool>(() => Find(paramE, paramF));     
Task.Factory.StartNew<bool>(() => Find(paramG, paramH));  

var result = found.WaitOne(TimeSpan.FromSeconds(10)); // wait with timeout of 10 secs

// do something with result

...
private static bool Find(int[,] m1, int[,] m2)          
{          
    if (found.WaitOne(0)) // check whether MSE has already been set
        return false;        

    // Do work...
    found.Set();
}
于 2012-08-06T08:48:42.723 に答える