为了执行长时间运行(让它在此上下文中搜索)操作,我将加载逻辑放在 TPL 任务中,因此在后台线程上调用通用方法 Search() 。 Search() 操作可能足够长,因此我需要能够使用 CancellationToken 正确取消它。 。但是Search()操作直到完成才返回,所以我必须做一些逻辑才能实现方便且(!)快速取消。
使用 WaitHandle's 我可以实现这样的东西:
private void StartSearch() // UI thread
{
CancellationTokenSource s = new CancellationTokenSource();
Task.Factory.StartNew(() => StartSearchInternal(s.Token), s.Token)
}
private void StartSearchInternal(CancellationToken token) // Main Background Thread
{
ManualResetEvent eHandle = new ManualResetEvent(false);
Task.Factory.StartNew(() => Search(eHandle ), TaskScheduler.Default);
WaitHandle.WaitAny(new [] { eHandle, token.WaitHandle });
token.ThrowIfCancellationRequested();
}
private IEnumerable<object> Search(ManualResetEvent e) // Another Background thread
{
try
{
// Real search call, i.e. to database, service, or AD, doesn't matter
return RealSearch();
}
catch {} // Here, for simplicity of question, catch and eat all exceptions
finally
{
try
{
e.Set();
}
catch {}
}
}
在我看来,这并不是一个优雅的解决方案。
问:还有其他方法可以完成此任务吗?
最佳答案
如果您可以控制 StartSearchInternal()
和 Search(eHandle)
,那么您应该能够使用内部的 ThrowIfCancellationRequested
进行协作取消您的Search
核心循环。
有关更多详细信息,我强烈建议阅读此文档:"Using Cancellation Support in .NET Framework 4" .
顺便说一句,您可能应该将对 Task.Factory.StartNew(() => StartSearchInternal(s.Token), s.Token)
返回的任务的引用存储在您的某个位置 View 模型类。您很可能想要观察其结果以及它可能引发的任何异常。您可能想查看 Lucian Wischik 的 "Async re-entrancy, and the patterns to deal with it" .
关于c# - 具有取消能力的长时间运行操作模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23539397/