杀了僵持任务在.NET 4 TPL [英] Killing a deadlocked Task in .NET 4 TPL

查看:131
本文介绍了杀了僵持任务在.NET 4 TPL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开始使用href="http://msdn.microsoft.com/en-us/library/dd460717.aspx">任务并行库的

I'd like to start using the Task Parallel Library, as this is the recommended framework going forward for performing asynchronous operations. One thing I haven't been able to find is any means of forcible Abort, such as what Thread.Abort provides.

我特别担心的是,我计划运行code,我不希望完全信任的任务。特别是,我不能肯定这不可信code不会死锁,因此,如果一个任务我计划使用这种code将永远完整的我不能肯定。我想远离真实的AppDomain隔离(由于开销和编组的复杂性),但我也不想留下一个任务线程游逛,僵持不下。有没有办法做到这一点在TPL?

My particular concern is that I schedule tasks running code that I don't wish to completely trust. In particular, I can't be sure this untrusted code won't deadlock and therefore I can't be certain if a Task I schedule using this code will ever complete. I want to stay away from true AppDomain isolation (due to the overhead and complexity of marshaling), but I also don't want to leave a Task thread hanging around, deadlocked. Is there a way to do this in TPL?

推荐答案

要做到这一点的方法是使用的CancellationToken和新的取消模型。 新的取消模型集成到.NET框架的几种类​​型。最重要的是System.Threading.Tasks,System.Threading.Tasks.Task,System.Threading.Tasks.Task和System.Linq.ParallelEnumerable。

The way to do this is with a CancellationToken and the new cancellation model. The new cancellation model is integrated into the .NET Framework in several types. The most important ones are System.Threading.Tasks, System.Threading.Tasks.Task, System.Threading.Tasks.Task and System.Linq.ParallelEnumerable.

下面是你的问题的一个例子。这code将始终死锁,因为调用code需要的锁,然后再陷入僵局的任务试图将收购同一个锁。

Here's an example of your problem. This code will always deadlock because the calling code takes a lock first and then the deadlocked task tries to aquire the same lock.

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任务取消是协作。换句话说,这将永远死锁,因为没有处理取消标记被设置为取消,因为任务线程被锁定。

Task cancellation in the TPL is cooperative. In other words this will always deadlock because nothing handles the cancellation token being set to cancelled because the task thread is locked.

有解决的办法,但它仍然依赖于非信任code做正确的事作者:

There is a way around this but it still relies on the authors of the untrusted code to do the right thing:

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得到处理,并等待它连同其他同步原语的手柄(S)。互斥比监视器(或锁定)慢得多。

Points to note; cancellation is cooperative. You can use Token.WaitHandle to get a handle and wait on it along with the handle(s) of other synchronization primitives. Mutex is much slower than Monitor (or lock).

真的,如果你不信任的code,足有撰文他们实施的合作取消,那么我怀疑让他们的AppDomain中在同一个线程中运行的理智。

Really if you don't trust the author of the code enough to have them implement cooperative cancellation then I'd question the sanity of having them run inside your AppDomain on the same thread.

有关进一步的细节,请参见:

For further detail see:

<一个href="http://msdn.microsoft.com/en-us/library/dd997364.aspx">http://msdn.microsoft.com/en-us/library/dd997364.aspx

<一个href="http://msdn.microsoft.com/en-us/library/dd537607.aspx">http://msdn.microsoft.com/en-us/library/dd537607.aspx

<一个href="http://msdn.microsoft.com/en-us/library/ee191552.aspx">http://msdn.microsoft.com/en-us/library/ee191552.aspx

这篇关于杀了僵持任务在.NET 4 TPL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆