调用Wait()或WaitAll()时,任务总是取消

时间:2014-09-26 15:01:28

标签: c# task-parallel-library task

我有一个名为TaskManager的Task.Factory.StartNew的包装器,我需要实现它以便在新线程中添加异常处理。这是我的班级:

public static class TaskManager
{
    public static Task StartNew(Action action, IUserContextBase userContext, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action), userContext, null, onCompletedCallback);
    }

    public static Task StartNew(Action action, IUserContextBase userContext, CancellationToken cancellationToken, TaskCreationOptions taskCreationOptions, TaskScheduler taskScheduler, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action, cancellationToken, taskCreationOptions, taskScheduler), userContext, null, onCompletedCallback);
    }

    public static Task StartNew(Action action, IUserContextBase userContext, TaskCreationOptions taskCreationOptions, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action, taskCreationOptions), userContext, null, onCompletedCallback);
    }

    public static Task StartNew(Action<object> action, IUserContextBase userContext, object state, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action, state), userContext, null, onCompletedCallback);
    }

    public static Task StartNew(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions taskCreationOptions, TaskScheduler taskScheduler, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action, null, cancellationToken, taskCreationOptions, taskScheduler), null, null, onCompletedCallback);
    }

    public static Task StartNew(Action<object> action, object state, Action<System.Exception> onExceptionCallback = null, Action<Task> onCompletedCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action, state), null, onExceptionCallback, onCompletedCallback);
    }

    public static Task StartNew(Action action, Action<System.Exception> onExceptionCallback = null)
    {
        return AddContinueWithToTask(Task.Factory.StartNew(action), null, onExceptionCallback);
    }

    public static Task<TResult> StartNew<TResult>(Func<TResult> function, IUserContextBase userContext, CancellationToken cancellationToken)
    {
        return Task.Factory.StartNew(function, cancellationToken).ContinueWith(t =>
        {
            ManageException(t, userContext);
            return t.Result;
        }, TaskContinuationOptions.OnlyOnFaulted);
    }

    private static void ManageException(Task t, IUserContextBase userContext, Action<System.Exception> onExceptionCallback = null)
    {
        if (t.Exception != null)
            if (onExceptionCallback != null)
                onExceptionCallback(t.Exception);
            else
                t.Exception.Handle(ex =>
                {
                    GlobalContainer.Unity.Resolve<IDiagnosticLogHandler>().LogError(userContext, ex, ErrorSeverity.Normal);
                    return true;
                });          
    }

    private static Task AddContinueWithToTask(Task task, IUserContextBase userContext, Action<System.Exception> onExceptionCallback = null, Action<Task> onCompletedCallback = null)
    {
        return task
            .ContinueWith(t => ManageException(t, userContext, onExceptionCallback), TaskContinuationOptions.OnlyOnFaulted)
            .ContinueWith(t2 => { if (onCompletedCallback != null) onCompletedCallback(t2); })
            .ContinueWith(t => ManageException(t, userContext, onExceptionCallback), TaskContinuationOptions.OnlyOnFaulted);
    }

但是,每当有人使用我的类(它返回一个Task),然后调用task.Wait()或task.WaitAll()之后,他们似乎得到一个异常,说任务已经(全部)被取消了。 Wait()或WaitAll()发生错误。我的TaskManager类有什么问题?

2 个答案:

答案 0 :(得分:2)

您实际上是将原始任务的延续返回给调用者而不是实际任务。

您的延续时间为TaskContinuationOptions.OnlyOnFaulted,这意味着只有在前因出现故障时才运行,否则取消。因此,您会看到来电者获得TaskCancelledException

换句话说,当实际任务运行至完成时,将取消继续。当实际任务出现故障时,如果使用TaskContinuationOptions.OnlyOnFaulted,则“运行至完成

要修复它,您需要将实际任务返回给调用者,但添加延续并随身携带。

更新:要返回原始任务,只需使用本地变量。

public static Task StartNew(Action action, Action<System.Exception> onExceptionCallback = null)
{
    var actualTask = Task.Factory.StartNew(action);
    AddContinueWithToTask(actualTask, null, onExceptionCallback);
    return actualTask;
}
...

答案 1 :(得分:0)

问题在于,您将t2任务链接到一个永不运行的任务的末尾,因为它已设置为OnlyOnFaulted

试试这个: -

        private static Task AddContinueWithToTask(Task task, object userContext, Action<System.Exception> onExceptionCallback = null, Action<Task> onCompletedCallback = null)
        {
            return task
                .ContinueWith(t => {
                    if (t.IsFaulted)
                        ManageException(t, userContext, onExceptionCallback);
                })
                .ContinueWith(t2 => 
                {
                    if (onCompletedCallback != null) onCompletedCallback(t2); 
                })
                .ContinueWith(t => {
                    if (t.IsFaulted)
                        ManageException(t, userContext, onExceptionCallback);
                })
                ;
        }

来自Task.Continuewith

上的MSDN
  

在当前任务完成之前,不会安排返回的任务执行   完成。如果通过continuationOptions参数指定的条件是   如果没有达到,延续任务将被取消而不是安排。