看了上一篇C# Task 是什么?返回值如何实现? Wait如何实现 我们提到FinishContinuations方法中会调用TaskContinuation实例,那么我们的ContinueWith就应该非常简单,只需要把TASK放到TaskContinuation结合中就可以了,ContinueWith可以是 Action<Task<TResult>>也可以是 Func<Task<TResult>,TNewResult> ,其中Task<TResult>的实现如下:

 public class Task<TResult> : Task{
//Creates a continuation that executes when the target Task{TResult}" completes
public Task ContinueWith(Action<Task<TResult>> continuationAction)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
}
internal Task ContinueWith(Action<Task<TResult>> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken,TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
{
if (continuationAction == null)
{
throw new ArgumentNullException("continuationAction");
}
if (scheduler == null)
{
throw new ArgumentNullException("scheduler");
}
TaskCreationOptions creationOptions;
InternalTaskOptions internalOptions;
CreationOptionsFromContinuationOptions(continuationOptions,out creationOptions,out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask<TResult>(this, continuationAction, null, creationOptions, internalOptions,ref stackMark);
ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions);
return continuationTask;
} public Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith<TNewResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
} // Same as the above overload, just with a stack mark.
internal Task<TNewResult> ContinueWith<TNewResult>(Func<Task<TResult>, Object, TNewResult> continuationFunction, Object state,TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
{
if (continuationFunction == null)
{
throw new ArgumentNullException("continuationFunction");
}
if (scheduler == null)
{
throw new ArgumentNullException("scheduler");
} TaskCreationOptions creationOptions;
InternalTaskOptions internalOptions;
CreationOptionsFromContinuationOptions(continuationOptions,out creationOptions,out internalOptions); Task<TNewResult> continuationFuture = new ContinuationResultTaskFromResultTask<TResult,TNewResult>(this, continuationFunction, state,creationOptions, internalOptions,ref stackMark);
ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions);
return continuationFuture;
}
}

ContinueWith的核心是调用Task的ContinueWithCore方法,这里把我们的Action或Fun包装成子的Task,比如这里的ContinuationResultTaskFromResultTask实现【很是标准】如下:

 internal sealed class ContinuationResultTaskFromResultTask<TAntecedentResult, TResult> : Task<TResult>
{
private Task<TAntecedentResult> m_antecedent;
public ContinuationResultTaskFromResultTask(
Task<TAntecedentResult> antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark) :
base(function, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, internalOptions, null)
{
Contract.Requires(function is Func<Task<TAntecedentResult>, TResult> || function is Func<Task<TAntecedentResult>, object, TResult>, "Invalid delegate type in ContinuationResultTaskFromResultTask");
m_antecedent = antecedent;
PossiblyCaptureContext(ref stackMark);
} internal override void InnerInvoke()
{
var antecedent = m_antecedent;
Contract.Assert(antecedent != null, "No antecedent was set for the ContinuationResultTaskFromResultTask.");
m_antecedent = null;
antecedent.NotifyDebuggerOfWaitCompletionIfNecessary(); // Invoke the delegate
Contract.Assert(m_action != null);
var func = m_action as Func<Task<TAntecedentResult>, TResult>;
if (func != null)
{
m_result = func(antecedent);
return;
}
var funcWithState = m_action as Func<Task<TAntecedentResult>, object, TResult>;
if (funcWithState != null)
{
m_result = funcWithState(antecedent, m_stateObject);
return;
}
Contract.Assert(false, "Invalid m_action in ContinuationResultTaskFromResultTask");
}
}

ContinuationResultTaskFromResultTask<TAntecedentResult, TResult> 就重写基类Task的InnerInvoke方法,现在回到Task的ContinueWithCore方法:

public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
{
/// Registers the continuation and possibly runs it (if the task is already finished).
internal void ContinueWithCore(Task continuationTask, TaskScheduler scheduler,CancellationToken cancellationToken, TaskContinuationOptions options)
{
Contract.Requires(continuationTask != null, "Task.ContinueWithCore(): null continuationTask");
Contract.Requires(scheduler != null, "Task.ContinueWithCore(): null scheduler");
Contract.Requires(!continuationTask.IsCompleted, "Did not expect continuationTask to be completed"); // Create a TaskContinuation
TaskContinuation continuation = new StandardTaskContinuation(continuationTask, options, scheduler); // If cancellationToken is cancellable, then assign it.
if (cancellationToken.CanBeCanceled)
{
if (IsCompleted || cancellationToken.IsCancellationRequested)
{
continuationTask.AssignCancellationToken(cancellationToken, null, null);
}
else
{
continuationTask.AssignCancellationToken(cancellationToken, this, continuation);
}
} // In the case of a pre-canceled token, continuationTask will have been completed
// in a Canceled state by now. If such is the case, there is no need to go through
// the motions of queuing up the continuation for eventual execution.
if (!continuationTask.IsCompleted)
{
if ((this.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != && !(this is ITaskCompletionAction))
{
var etwLog = TplEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, Task.CurrentId ?? , continuationTask.Id);
}
} // Attempt to enqueue the continuation
bool continuationQueued = AddTaskContinuation(continuation, addBeforeOthers: false); // If the continuation was not queued (because the task completed), then run it now.
if (!continuationQueued) continuation.Run(this, bCanInlineContinuationTask: true);
}
} private bool AddTaskContinuation(object tc, bool addBeforeOthers)
{
Contract.Requires(tc != null);
if (IsCompleted) return false; // Try to just jam tc into m_continuationObject
if ((m_continuationObject != null) || (Interlocked.CompareExchange(ref m_continuationObject, tc, null) != null))
{
return AddTaskContinuationComplex(tc, addBeforeOthers);
}
else return true;
} private bool AddTaskContinuationComplex(object tc, bool addBeforeOthers)
{
Contract.Requires(tc != null, "Expected non-null tc object in AddTaskContinuationComplex");
object oldValue = m_continuationObject;
// Logic for the case where we were previously storing a single continuation
if ((oldValue != s_taskCompletionSentinel) && (!(oldValue is List<object>)))
{
List<object> newList = new List<object>();
newList.Add(oldValue);
Interlocked.CompareExchange(ref m_continuationObject, newList, oldValue);
} // m_continuationObject is guaranteed at this point to be either a List or
// s_taskCompletionSentinel.
List<object> list = m_continuationObject as List<object>;
Contract.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel),"Expected m_continuationObject to be list or sentinel");
if (list != null)
{
lock (list)
{
if (m_continuationObject != s_taskCompletionSentinel)
{
// Before growing the list we remove possible null entries that are the
// result from RemoveContinuations()
if (list.Count == list.Capacity)
{
list.RemoveAll(s_IsTaskContinuationNullPredicate);
} if (addBeforeOthers)
list.Insert(0, tc);
else
list.Add(tc); return true; // continuation successfully queued, so return true.
}
}
}
// We didn't succeed in queuing the continuation, so return false.
return false;
} /// Handles everything needed for associating a CancellationToken with a task which is being constructed.
/// This method is meant to be be called either from the TaskConstructorCore or from ContinueWithCore
private void AssignCancellationToken(CancellationToken cancellationToken, Task antecedent, TaskContinuation continuation)
{
ContingentProperties props = EnsureContingentPropertiesInitialized(needsProtection: false);
props.m_cancellationToken = cancellationToken; try
{
if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
{
cancellationToken.ThrowIfSourceDisposed();
}
if ((((InternalTaskOptions)Options & (InternalTaskOptions.QueuedByRuntime | InternalTaskOptions.PromiseTask | InternalTaskOptions.LazyCancellation)) == ))
{
if (cancellationToken.IsCancellationRequested)
{
// Fast path for an already-canceled cancellationToken
this.InternalCancel(false);
}
else
{
// Regular path for an uncanceled cancellationToken
CancellationTokenRegistration ctr;
if (antecedent == null)
{
ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback, this);
}
else
{
ctr = cancellationToken.InternalRegisterWithoutEC(s_taskCancelCallback,new Tuple<Task, Task, TaskContinuation>(this, antecedent, continuation));
}
props.m_cancellationRegistration = new Shared<CancellationTokenRegistration>(ctr);
}
}
}
catch
{
if ((m_parent != null) &&((Options & TaskCreationOptions.AttachedToParent) != )&& ((m_parent.Options & TaskCreationOptions.DenyChildAttach) == ))
{
m_parent.DisregardChild();
}
throw;
}
} private readonly static Action<Object> s_taskCancelCallback = new Action<Object>(TaskCancelCallback);
private static void TaskCancelCallback(Object o)
{
var targetTask = o as Task;
if (targetTask == null)
{
var tuple = o as Tuple<Task, Task, TaskContinuation>;
if (tuple != null)
{
targetTask = tuple.Item1; Task antecedentTask = tuple.Item2;
TaskContinuation continuation = tuple.Item3;
antecedentTask.RemoveContinuation(continuation);
}
}
Contract.Assert(targetTask != null,"targetTask should have been non-null, with the supplied argument being a task or a tuple containing one");
targetTask.InternalCancel(false);
}
}

ContinueWithCore实现也比较简单,首先把当前的continuationTask转换为StandardTaskContinuation,然后把CancellationToken赋给continuationTask,如果continuationTask没有完成, 那么调用AddTaskContinuation把continuationTask加到等待对象中,如果AddTaskContinuation添加失败,就直接调用continuationTask。 让我妈来看看StandardTaskContinuation的实现:

 internal abstract class TaskContinuation
{
internal abstract void Run(Task completedTask, bool bCanInlineContinuationTask); /// <summary>Tries to run the task on the current thread, if possible; otherwise, schedules it.</summary>
protected static void InlineIfPossibleOrElseQueue(Task task, bool needsProtection)
{
Contract.Requires(task != null);
Contract.Assert(task.m_taskScheduler != null);
if (needsProtection)
{
if (!task.MarkStarted())
return; // task has been previously started or canceled. Stop processing.
}
else
{
task.m_stateFlags |= Task.TASK_STATE_STARTED;
} // Try to inline it but queue if we can't
try
{
if (!task.m_taskScheduler.TryRunInline(task, taskWasPreviouslyQueued: false))
{
task.m_taskScheduler.InternalQueueTask(task);
}
}
catch (Exception e)
{ if (!(e is ThreadAbortException && (task.m_stateFlags & Task.TASK_STATE_THREAD_WAS_ABORTED) != )) // this ensures TAEs from QueueTask will be wrapped in TSE
{
TaskSchedulerException tse = new TaskSchedulerException(e);
task.AddException(tse);
task.Finish(false);
}
}
}
internal abstract Delegate[] GetDelegateContinuationsForDebugger();
} /// <summary>Provides the standard implementation of a task continuation.</summary>
internal class StandardTaskContinuation : TaskContinuation
{
internal readonly Task m_task;
internal readonly TaskContinuationOptions m_options;
private readonly TaskScheduler m_taskScheduler;
internal StandardTaskContinuation(Task task, TaskContinuationOptions options, TaskScheduler scheduler)
{
Contract.Requires(task != null, "TaskContinuation ctor: task is null");
Contract.Requires(scheduler != null, "TaskContinuation ctor: scheduler is null");
m_task = task;
m_options = options;
m_taskScheduler = scheduler;
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, m_task.Id, "Task.ContinueWith: " + ((Delegate)task.m_action).Method.Name, ); if (Task.s_asyncDebuggingEnabled)
{
Task.AddToActiveTasks(m_task);
}
} /// <summary>Invokes the continuation for the target completion task.</summary>
/// <param name="completedTask">The completed task.</param>
/// <param name="bCanInlineContinuationTask">Whether the continuation can be inlined.</param>
internal override void Run(Task completedTask, bool bCanInlineContinuationTask)
{
Contract.Assert(completedTask != null);
Contract.Assert(completedTask.IsCompleted, "ContinuationTask.Run(): completedTask not completed"); // Check if the completion status of the task works with the desired
// activation criteria of the TaskContinuationOptions.
TaskContinuationOptions options = m_options;
bool isRightKind =
completedTask.IsRanToCompletion ?
(options & TaskContinuationOptions.NotOnRanToCompletion) == :
(completedTask.IsCanceled ?
(options & TaskContinuationOptions.NotOnCanceled) == :
(options & TaskContinuationOptions.NotOnFaulted) == ); // If the completion status is allowed, run the continuation.
Task continuationTask = m_task;
if (isRightKind)
{
if (!continuationTask.IsCanceled && AsyncCausalityTracer.LoggingOn)
{
// Log now that we are sure that this continuation is being ran
AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, continuationTask.Id, CausalityRelation.AssignDelegate);
}
continuationTask.m_taskScheduler = m_taskScheduler; if (bCanInlineContinuationTask && // inlining is allowed by the caller
(options & TaskContinuationOptions.ExecuteSynchronously) != ) // synchronous execution was requested by the continuation's creator
{
InlineIfPossibleOrElseQueue(continuationTask, needsProtection: true);
}
else
{
try { continuationTask.ScheduleAndStart(needsProtection: true); }
catch (TaskSchedulerException)
{
// No further action is necessary -- ScheduleAndStart() already transitioned the
// task to faulted. But we want to make sure that no exception is thrown from here.
}
}
}
// Otherwise, the final state of this task does not match the desired
// continuation activation criteria; cancel it to denote this.
else continuationTask.InternalCancel(false);
}
internal override Delegate[] GetDelegateContinuationsForDebugger()
{
if (m_task.m_action == null)
{
return m_task.GetDelegateContinuationsForDebugger();
}
return new Delegate[] { m_task.m_action as Delegate };
}
}

StandardTaskContinuation的实现非常简单,而Task的AssignCancellationToken方法也没什么可以说的,只是需要注意下一下回调s_taskCancelCallback。Task的AddTaskContinuation方法首先检查当前Task是否结束,结束了就不用再调用AddTaskContinuationComplex方法了,直接调用continuation.Run方法,AddTaskContinuationComplex方法会把task添加到m_continuationObject中,最后FinishContinuations在调用m_continuationObject中的TaskContinuation.Run方法。

总结一下:ContinueWith方法主要调用ContinueWithCore方法,ContinueWithCore方法主要是调用AddTaskContinuation,AddTaskContinuation方法把Task加到m_continuationObject,【如果主的Task已经完成,那么这里AddTaskContinuation返回false,则直接调用TaskContinuation.Run】,当主的Task完成时会调用FinishContinuations方法,FinishContinuations方法会检测m_continuationObject中TaskContinuation对象,一次调用它们的Run方法。

C# Task ContinueWith的实现的更多相关文章

  1. Web Api 图片上传,在使用 Task.ContinueWith 变量无法赋值问题

    细谈 Web Api 图片上传,在使用 Task.ContinueWith 变量无法赋值问题的解决办法!   在使用Asp.Net Web Api 图片上传接口的时候,到网上找了一些个例子,但大多数找 ...

  2. Task ContinueWith

    前正无生意,且记Task.ContinueWith之用法. using System; using System.Collections.Generic; using System.Diagnosti ...

  3. 细谈 Web Api 图片上传,在使用 Task.ContinueWith 变量无法赋值问题的解决办法!

    在使用Asp.Net Web Api 图片上传接口的时候,到网上找了一些个例子,但大多数找到都是这个版本! [HttpPost] public Task<Hashtable> ImgUpl ...

  4. C# Task ContinueWith

    static void Main(string[] args) { Task firstTask = Task.Run(() => { PrintPlus(); }); Task secondT ...

  5. 2、Task 使用 ContinueWith 而不要使用 Wait

    1.线程自旋:在阻塞线程的时候为了等待解锁(访问临界资源)(Sleep). 2.上下文切换:将处理器当前线程的状态保存到操作系统内部的线程对象中,然后再挑出一个就绪的线程,把上下文信息传递给处理器,然 ...

  6. Task类学习教程—组合任务ContinueWith

    Task类学习教程-组合任务.ContinueWith 一.简介 通过任务,可以指定在任务完成之后,应开始运行之后另一个特定任务.ContinueWith是Task根据其自身状况,决定后续应该作何操作 ...

  7. .Net多线程编程—任务Task

    1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...

  8. 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)

    Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下) 多 Task 的并行执行 Parallel - 并行计算(在 System.Threading.Task ...

  9. c# .Net并行和多线程编程之Task学习记录!

    任务Task和线程Thread的区别: 1.任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行. 2.任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线 ...

随机推荐

  1. net core体系-web应用程序-4asp.net core2.0 项目实战(1)-9项目各种全局帮助类

    本文目录 1.  前沿2.CacheHelper基于Microsoft.Extensions.Caching.Memory封装3.XmlHelper快速操作xml文档4.SerializationHe ...

  2. 系统环境变量(就是不需要切换目录,敲击“python”就可以进入编码器)

    1.右击我的电脑,选择属性,选择“高级系统设置” 2.选择高级,选择环境变量 3.在系统变量中找到path,点击编辑.然后新建,将python的路径复制进去,点击确定.

  3. ConcurrentModificationException(并发修改异常)的分析

    1)介绍 并发修改ConcurrentModificationException错误是开发中一个常见错误,多发生在对一个Collection边遍历边做影响size变化的操作中,下面以ArrayList ...

  4. day7 [id],[is],编码

    老师的笔记: 字典:dic = {'name':'alex'} 1,增 dic['k'] = 'v' 有键值对,则覆盖 setdefault 有键值对,不添加 dic.setdefault('k1', ...

  5. HDU-1013的解题报告

    题目来源:hdu-1013 题意:正整数的数字根是通过求整数的整数而求出的.如果结果值是一个位数,那么这个数字就是数字根.如果结果值包含两个或多个数字,则将这些数字相加并重复该过程.只要需要获得一个数 ...

  6. java中path和CLASSPATH的配置和意义解析

    原文链接 https://blog.csdn.net/eclipse_yin/article/details/51447169 一.JDK的安装和基本配置 JDK的安装: 1) 如果想要获得JDK,那 ...

  7. 使用pdfBox实现pdf转图片,解决中文方块乱码等问题

    一.引入依赖 <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>fontbox ...

  8. Alpha(6/10)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...

  9. vue(v-html)和scss的使用问题

    <!--temp是一组p标签--> <div class="lyric-container" v-html="temp"></di ...

  10. JS 对象引用问题

    var a = {n:1}; var b = a; a = {n:2}; a.x = a ;console.log(a.x);console.log(b.x); var a = {n:1}; var ...