C# 如何在有条件的情况下等待任务?

C# 如何在有条件的情况下等待任务?,c#,task-parallel-library,task,C#,Task Parallel Library,Task,我有一些任务返回bool。我只想先等到任何任务返回True。可能吗 我的第一个想法是使用CancellationTokenSource,但这不是一个好主意,因为当我调用Task.WaitAll方法时,它会引发一个异常 第二个选项是使用bool I pass-in引用,如果为真,则直接返回。它可以工作,但不起作用: bool isFound = false; Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(

我有一些任务返回bool。我只想先等到任何任务返回True。可能吗

我的第一个想法是使用CancellationTokenSource,但这不是一个好主意,因为当我调用Task.WaitAll方法时,它会引发一个异常

第二个选项是使用bool I pass-in引用,如果为真,则直接返回。它可以工作,但不起作用:

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;
编辑:

作为预先设定的答案,我现在使用
TaskCompletionSource

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;

但它不起作用:(

您需要。在一开始,您设置了一个
WaitHandle[]
,当任务成功执行时,每个人都等待一个
任务(并按照您的预期结果获得
true
),您可以向相应的
WaitHandle

发送信号,其中一个选项是创建您想要的任何类型的
TaskCompletionSource
(如果需要,标识结果)。然后向每个任务添加一个延续,如果结果为true,则调用

然后只需等待
TaskCompletionSource.Task
。这样可以避免重复调用、检查结果等

棘手的一点是注意到所有任务何时返回false…在.NET4.5中,这相当容易,通过-创建另一个任务,然后您只需等待
{success,all failed}
中的第一个任务完成。

您可以使用一个可以使
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();
}
private static ManualResetEvent found=新的ManualResetEvent(false);
...
Task.Factory.StartNew(()=>Find(paramA,paramB));
Task.Factory.StartNew(()=>Find(paramC,paramD));
Task.Factory.StartNew(()=>Find(paramE,paramF));
Task.Factory.StartNew(()=>Find(paramG,paramH));
var result=found.WaitOne(TimeSpan.FromSeconds(10));//等待,超时10秒
//做一些有结果的事情
...
专用静态布尔查找(int[,]m1,int[,]m2)
{          
if(found.WaitOne(0))//检查是否已设置MSE
返回false;
//做工作。。。
found.Set();
}

难道你不想使用WaitAny而不是WaitAll吗?当任务返回true时,它会很好地工作。但是我正在尝试处理任务。Whalll,但似乎什么都没有被注意到…@Florian:那么你是在使用.NET 4.5吗?可能值得更新这个问题,或者为
Whalll
案例启动一个新的问题。基本上你是在追求“第一个{任何返回true的,都已返回}"是的,我使用的是.Net 4.5。我想我误用了.WhenAll方法。我会更新问题是的-我猜他实际上想要
WaitAny
,但不清楚他想做什么。在第一个问题中,他只是从所有答案中XOR。在第二次迭代中,他在
TrySetResult
中设置了一个结果,没有任何XOR。所以我当所有的
和任何的都是好答案时,请使用这两个答案
tcs.Task.Wait();
Task tr = Task.WhenAll(new Task[] { t0, t1, t2, t3, t4 });

if (tr.IsCompleted)
    return false;
else
    return tcs.Task.Result;
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();
}