用于递归调用的Selective AttachedToParent

时间:2013-04-03 13:31:24

标签: .net .net-4.0 task-parallel-library

我已经实现了帮助方法,用于在后台执行繁重的任务

它接受多个代表并且不会阻止:

  • async part
  • 成功部分(GUI)
  • 异步部分(GUI)失败
  • finally(GUI)(可选)

每个gui部分都可以启动自己的序列,即发生对我的辅助方法的递归调用。但是,当附加任务完成时,我想将任何部分视为已完成。

这张照片解释了我的意思:

enter image description here

为了提供这种条件,我创建了我的异步任务作为附加到父母,这给了我我需要的东西 我唯一的问题是在TPL for .NET v4 DenyChildAttach选项不存在所以当我在其他任务中调用我的方法时它会附加到这个任务上。
我将创建一个带参数的重载来指示需要附加,但是我想要以下默认行为:

如果递归调用则附加,否则请勿附加,除非明确说明。
定义我应该设置一些指示递归的上下文,但不理解如何......

P.S。现在方法看起来像这样(对Action,Func有很多oveload):

public static CancellationTokenSource ExecuteBlockingOperation(Action action,
            Action completition,
            Action<AggregateException> onException,
            Action<bool, bool, bool> @finally = null)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            if (completition == null)
                throw new ArgumentNullException("completition");

            if (onException == null)
                throw new ArgumentNullException("onException");

            var cts = new CancellationTokenSource();
            var token = cts.Token;

            var scheduler = SynchronizationContext.Current == null? TaskScheduler.Default : TaskScheduler.FromCurrentSynchronizationContext();
            var successfullyCompleted = false;

            var task = new Task(action, TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent);
            var onFault = task.ContinueWith(asyncPartTask => onException(asyncPartTask.Exception),
                CancellationToken.None,
                TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent,
                scheduler);

            var onSuccess = task.ContinueWith(asyncPart =>
                {
                    if (!token.IsCancellationRequested)
                    {
                        completition();
                        successfullyCompleted = true;
                    }
                }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent, scheduler);

            if (@finally != null)
            {
                Task.Factory.ContinueWhenAll(new[] { onSuccess, onFault },
                    tasks =>
                    {
                        var isSuccess = task.Status == TaskStatus.RanToCompletion;
                        @finally(isSuccess, token.IsCancellationRequested, successfullyCompleted);
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.AttachedToParent, scheduler);
            }

            task.Start();

            return cts;

        }

1 个答案:

答案 0 :(得分:0)

我认为使用AttachedToParent非常笨拙。您可以做的是通过将Task更改为completition来明确让孩子Func<Task>。这样,您可以控制何时继续执行。

为此,您需要将onSuccess更改为:

var onSuccess = task.ContinueWith(asyncPart =>
    {
        token.ThrowIfCancellationRequested();

        return completion();
    }, token, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler).Unwrap();

这也很可能意味着ExecuteBlockingOperation()需要返回执行Task的{​​{1}},但我认为这应该不是问题。