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