我想开始使用Task Parallel Library,因为这是推荐的用于执行异步操作的框架。我无法找到的一件事是任何强制中止的方法,例如 Thread.Abort 提供的。
我特别担心的是我安排了运行我不希望完全信任的代码的任务。特别是,我不能确定这个不受信任的代码不会死锁,因此我不能确定我使用这个代码安排的任务是否会完成。我想远离真正的 AppDomain 隔离(由于编组的开销和复杂性),但我也不想让 Task 线程悬而未决,陷入僵局。有没有办法在 TPL 中做到这一点?
我想开始使用Task Parallel Library,因为这是推荐的用于执行异步操作的框架。我无法找到的一件事是任何强制中止的方法,例如 Thread.Abort 提供的。
我特别担心的是我安排了运行我不希望完全信任的代码的任务。特别是,我不能确定这个不受信任的代码不会死锁,因此我不能确定我使用这个代码安排的任务是否会完成。我想远离真正的 AppDomain 隔离(由于编组的开销和复杂性),但我也不想让 Task 线程悬而未决,陷入僵局。有没有办法在 TPL 中做到这一点?
做到这一点的方法是使用 CancellationToken 和新的取消模型。新的取消模型以多种类型集成到 .NET Framework 中。最重要的是 System.Threading.Tasks、System.Threading.Tasks.Task、System.Threading.Tasks.Task 和 System.Linq.ParallelEnumerable。
这是您的问题的一个示例。此代码将始终死锁,因为调用代码首先获取锁,然后死锁任务尝试获取相同的锁。
public void Example()
{
object sync = new Object();
lock (sync)
{
CancellationTokenSource canceller = new CancellationTokenSource();
ManualResetEvent started = new ManualResetEvent(false);
Task deadlocked = Task.Factory.StartNew(() =>
{
started.Set();
// EVIL CODE: This will ALWAYS deadlock
lock(sync) { };
},
canceller.Token);
// Make sure task has started.
started.WaitOne();
canceller.Cancel();
try
{
// Wait for task to cancel.
deadlocked.Wait();
}
catch (AggregateException ex)
{
// Ignore canceled exception. SIMPLIFIED!
if (!(ex.InnerException is TaskCanceledException))
throw;
}
}
}
TPL 中的任务取消是合作的。换句话说,这将始终死锁,因为由于任务线程被锁定,没有任何东西处理被设置为取消的取消令牌。
有一种方法可以解决这个问题,但它仍然依赖不受信任的代码的作者来做正确的事情:
public static void Example2()
{
Mutex sync = new Mutex(true);
CancellationTokenSource canceller = new CancellationTokenSource();
bool started = false;
Task deadlocked = Task.Factory.StartNew(() =>
{
started = true;
// EVIL CODE: This will ALWAYS deadlock
WaitHandle.WaitAny(new WaitHandle[] { canceller.Token.WaitHandle, sync });
},
canceller.Token);
// Make sure task has started.
while (!started) { }
canceller.Cancel();
try
{
// Wait for task to cancel.
deadlocked.Wait();
}
catch (AggregateException ex)
{
// Ignore canceled exception. SIMPLIFIED!
if (!(ex.InnerException is TaskCanceledException))
throw;
}
}
注意事项;取消是合作的。您可以使用 Token.WaitHandle 获取句柄并与其他同步原语的句柄一起等待它。互斥锁比监视器(或锁)慢得多。
真的,如果您不信任代码的作者足以让他们实现合作取消,那么我会质疑让它们在同一线程上的 AppDomain 中运行的合理性。
更多详情请参见:
http://msdn.microsoft.com/en-us/library/dd997364.aspx
Dan 我不认为 Task.Wait(timeout) 会取消这个任务,有 Overload Task.Wait(timeout,cancelationToken),但是当令牌发出信号时,只会在 task.Wait 上抛出 OperationCanceledException。
Task.Wait 只会阻塞直到任务完成或超时到期,它不会取消或中止任务本身。所以死锁的任务会一直挂在线程池中。您不能处置未完成的任务 (InvalidOperation)。
我正在编写与您相同的应用程序,并且我确实编写了自己的 taskScheduler 允许中止(并且不使用线程池:()。
但我很好奇你是如何解决这个问题的。请回复我。
您只需调用Task.Wait(timespanToWait)
.
如果任务在指定的时间跨度后未完成,则将其取消。