杀死.NET 4 TPL中的死锁任务

杀死.NET 4 TPL中的死锁任务,.net,deadlock,parallel-processing,task,task-parallel-library,.net,Deadlock,Parallel Processing,Task,Task Parallel Library,我想开始使用,因为这是执行异步操作的推荐框架。有一件事我还没有找到强制中止的方法,比如Thread.Abort提供了什么 我特别关心的是,我安排的任务运行我不希望完全信任的代码。特别是,我不能确定这个不受信任的代码不会死锁,因此我不能确定使用此代码计划的任务是否会完成。我想远离真正的AppDomain隔离(由于封送处理的开销和复杂性),但我也不想让任务线程处于死锁状态。在第三方物流中有这样做的方法吗?您只需调用Task.Wait(timespanToWait) 如果任务在指定的时间间隔后未完成,

我想开始使用,因为这是执行异步操作的推荐框架。有一件事我还没有找到强制中止的方法,比如Thread.Abort提供了什么


我特别关心的是,我安排的任务运行我不希望完全信任的代码。特别是,我不能确定这个不受信任的代码不会死锁,因此我不能确定使用此代码计划的任务是否会完成。我想远离真正的AppDomain隔离(由于封送处理的开销和复杂性),但我也不想让任务线程处于死锁状态。在第三方物流中有这样做的方法吗?

您只需调用
Task.Wait(timespanToWait)

如果任务在指定的时间间隔后未完成,则会取消该任务。

Dan 我不认为Task.Wait(超时)会取消此任务,存在过载Task.Wait(超时,cancelationToken),但这只会在Task上引发OperationCanceledException。当标记发出信号时等待

任务。仅在任务完成或超时过期之前等待,它不会取消或中止任务本身。所以死锁的任务将一直挂在线程池中。无法处理未完成的任务(无效操作)

我正在编写与您和我自己编写的taskScheduler相同的应用程序,它允许中止(并且不使用threadpool:())


但是我很好奇你是如何解决这个问题的。请回复我。

方法是使用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中是否明智

有关更多详细信息,请参见:


谢谢。这在文档中一点也不明显,但当您认为任务将您与如何安排和管理任务的任何细节隔离开来时,这是有道理的。您知道在等待返回后,我是否需要做一些特殊的事情才能安全地处理任务吗?这不是答案。Wait()就这样,等等。它不会取消/中止任务。经过进一步考虑,我决定,如果可能发生死锁,Thread.abort实际上只是掩盖任何潜在问题,因为状态可能已经损坏。因此,我认为终止失败是致命的(运营商可选择继续等待或终止申请)。这对于我的应用程序来说已经足够了,因为它不是任务关键型的;如果应用程序是任务关键型的,我将不得不迁移到使用AppDomains或单独的托管进程来处理部分受信任的代码。Dan,我认为这是正确的思考方式。Thread.Abort绝对不是一个解决方案。它可能会让你的应用程序处于未知状态tate.谢谢,这是有用的信息。但是,我的印象是,听取消请求并在无法完全完成时自行抛出OperationCancelledException取决于任务。今天下午有机会时,我将试用您的代码。从第一个链接,“可以通过轮询、回调注册或等待等待句柄通知侦听器取消请求。”因此,任务有效。等待导致侦听发生。请参阅:有关使用IsCancellationRequested检查取消并对其作出响应的示例。代码似乎与描述的不一样。我仍然会遇到死锁(大约一半的时间)。虽然它可以工作,但它不能处理出现严重错误的情况,您需要中止。如果您使用第三方代码,您无法保证他们会做正确的事情。我希望MS能够解决这个问题。