平时我们开发中,经常使用Task,后续的.net版本种很多都和Task有关,比如asyn,await有了Task 我们很少就去关注Thread 了。Task 给我们带来了很多的便利之处。是我们更少的去关注执行的历程,更多的去关注逻辑。但是有些时候,有些应用。又不得不考虑task 的运行状况,比如这个任务成功与否,是否发生异常。经常听别人说到task 是在线程池执行的,那我们今天就来看看task 到底在做什么了,他执行的时候又做些哪些工作。

大家可以从这里可以看到Task 的源代码,也可以从reference code 直接download 下来。

我们先来看这段代码

public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
{
[ThreadStatic]
internal static Task t_currentTask; // The currently executing task.
[ThreadStatic]
private static StackGuard t_stackGuard; // The stack guard object for this thread internal static int s_taskIdCounter; //static counter used to generate unique task IDs
private readonly static TaskFactory s_factory = new TaskFactory(); private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested internal object m_action; // The body of the task. Might be Action<object>, Action<TState> or Action. Or possibly a Func.
// If m_action is set to null it will indicate that we operate in the
// "externally triggered completion" mode, which is exclusively meant
// for the signalling Task<TResult> (aka. promise). In this mode,
// we don't call InnerInvoke() in response to a Wait(), but simply wait on
// the completion event which will be set when the Future class calls Finish().
// But the event would now be signalled if Cancel() is called
}

先看Task 类继承的接口,IThreadPoolItem 这个和线程池相关,IAsyncResult这个和异步执行的回掉相关,这里我不在过多说这个,

接着我们看到有个字段t_currentTask ,而且是static 的,指向本身的task。大家不知道会不会有疑问,为什么这样设计呢,其实这样的设计在.net很多地方都有,比如HttpContext等等,特点基本都会有个Current。这种有点类似单例模式,但是开始已经初始化好,还有个更多的有点你可以随时替换,注入你自己的定义的东西。把他当作单例来用也是完全ok。注意了这里的访问修饰符是internal static。

接着t_stackGuard,s_taskIdCounter 顾名思义不在过多介绍。

下面就是s_factory 注意他是static 和访问修饰符,当然我如果用工厂模式,一般很少会把当前的工厂放在类内部来使用。哪天我要给我生产出的成品当然得这么做了。

接着一个比较重要的字段m_action ,执行体。大家是否记得在汇编里是如何执行所谓函数的,push a push b call xxxx。a,b 分别是参数,xxxx 为跳转地址 执行代码,参数的传递一般是通过stack 来传递。在net 这里直接放成object ,而且注释写的很清楚无非是那些委托。但是对一个函数来说,他的执行体就是call 的地址。

接着我们看下面的字段

        internal object m_stateObject; // A state object that can be optionally supplied, passed to action.
internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. internal readonly Task m_parent; // A task's parent, or null if parent-less. internal volatile int m_stateFlags;

m_stateObject 一猜也大概直到作用。

下面又是一个执行过程特别重要的字段m_taskScheduler,在执行过程比较重要。 大家平时windows 的平台的taskScheduler可能用的比较多,说到taskScheduler,功能也就是在合理时间安排合理的task 执行,实际上就是一个执行管理器。当然我们在sql server 的开发工具也有类似的工作,job 的执行,我们也是要选择执行计划的。当然这里的m_taskScheduler 也许是有本身的意思,都是任务调度器。当然task 默认的taskScheduler与我们刚刚提到的工具功能差距有点大。当然,大家有个印象,就是用来调度task 的。至于怎么调度,各自有各自的方案。

m_stateFlags 状态标志字段。一个Task 的执行,我当然很想直到他当前的状态,开始,结束,所以这个也好理解。本身在Thread 种就有很多状态。

继续看代码

   public void Start()
{
Start(TaskScheduler.Current);
}
public void Start(TaskScheduler scheduler)
{
// Read the volatile m_stateFlags field once and cache it for subsequent operations
int flags = m_stateFlags; // Need to check this before (m_action == null) because completed tasks will
// set m_action to null. We would want to know if this is the reason that m_action == null.
if (IsCompletedMethod(flags))
{
throw new InvalidOperationException(Environment.GetResourceString("Task_Start_TaskCompleted"));
} if (scheduler == null)
{
throw new ArgumentNullException("scheduler");
} var options = OptionsMethod(flags);
if ((options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != )
{
throw new InvalidOperationException(Environment.GetResourceString("Task_Start_Promise"));
}
if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != )
{
throw new InvalidOperationException(Environment.GetResourceString("Task_Start_ContinuationTask"));
} // Make sure that Task only gets started once. Or else throw an exception.
if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
{
throw new InvalidOperationException(Environment.GetResourceString("Task_Start_AlreadyStarted"));
} ScheduleAndStart(true);
}

我们平常都会用start方法,他会默认传入一个TaskScheduler,我们接着看下面的方法,最后调用的是ScheduleAndStart方法,不管前面的验证,我们重点看执行流程,要弄清这点,我们必须清楚TaskScheduler.Current

到底是什么类,他的功能是什么,如果我们自己去写TaskScheduler,那又该去写什么,完成哪些功能。

我们继续从reference code 找到TaskScheduler 类。我们先重点追踪Current ,先不管方法。

 public static TaskScheduler Current
{
get
{
TaskScheduler current = InternalCurrent;
return current ?? TaskScheduler.Default;
}
}
internal static TaskScheduler InternalCurrent
{
get
{
Task currentTask = Task.InternalCurrent;
return ( (currentTask != null)
&& ((currentTask.CreationOptions & TaskCreationOptions.HideScheduler) == )
) ? currentTask.ExecutingTaskScheduler : null;
}
}
默认我继续找到default 属性
public static TaskScheduler Default
{
get
{
return s_defaultTaskScheduler;
}
}
private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler();
我们一步一步追踪,终于找到了ThreadPoolTaskScheduler,这时终于可以task 把threadpool 联系起来了。

再看执行ScheduleAndStart之前,我们看下
  if (Interlocked.CompareExchange(ref m_taskScheduler, scheduler, null) != null)
这句的写法,null 判断再加上对象的赋值。这个我们可以在平时的代码中加以借用。
												

C# Task 源代码阅读(1)的更多相关文章

  1. C# Task 源代码阅读(2)

    上篇已经讲到Task 的默认的TaskScheduler 为ThreadPoolTaskScheduler. 这时我们回到原来的task 的start方法,在代码最后,调用了 ScheduleAndS ...

  2. 非常好!!!Linux源代码阅读——中断【转】

    Linux源代码阅读——中断 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/2_int.html 目录 为什么要有中断 中断的作用 中断的处 ...

  3. XV6源代码阅读-进程线程

    Exercise1 源代码阅读 1.基本头文件:types.h param.h memlayout.h defs.h x86.h asm.h mmu.h elf.h types.h:仅仅是定义uint ...

  4. Mongodb源代码阅读笔记:Journal机制

    Mongodb源代码阅读笔记:Journal机制 Mongodb源代码阅读笔记:Journal机制 涉及的文件 一些说明 PREPLOGBUFFER WRITETOJOURNAL WRITETODAT ...

  5. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

  6. 利用doxygen提高源代码阅读效率

    阅读开源项目的源代码是提高自己编程能力的好方法,而有一个好的源代码阅读工具无疑能够让你在阅读源代码时事半功倍.之前找过不少源代码阅读工具,像SourceInsight.sourcenav.scitoo ...

  7. CI框架源代码阅读笔记5 基准測试 BenchMark.php

    上一篇博客(CI框架源代码阅读笔记4 引导文件CodeIgniter.php)中.我们已经看到:CI中核心流程的核心功能都是由不同的组件来完毕的.这些组件类似于一个一个单独的模块,不同的模块完毕不同的 ...

  8. 淘宝数据库OceanBase SQL编译器部分 源代码阅读--Schema模式

    淘宝数据库OceanBase SQL编译器部分 源代码阅读--Schema模式 什么是Database,什么是Schema,什么是Table,什么是列,什么是行,什么是User?我们能够能够把Data ...

  9. CI框架源代码阅读笔记3 全局函数Common.php

    从本篇開始.将深入CI框架的内部.一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说.全局函数具有最高的载入优先权.因此大多数的框架中BootStrap ...

随机推荐

  1. devexpress实现模仿Win8桌面metro风格

    1.devexpress强大的控件库,可很容易的实现Win8桌面metro风格.使用的TileControl控件,拖动与Win效果相同.所有图片均来自网络资源.每个块也可实现如图所示的四种大小,如何实 ...

  2. Android开发10:传感器器及地图相关应用

    前言 啦啦啦~各位小伙伴们好~经过这一学期的Android知识的学习,我们学到了很多和Android开发相关的知识,这一学期的学习也要告一段落了. 一起进入我们今天的相关内容~这次我们将一起学习使用 ...

  3. P177 test 6-4 UVa439

    //P177 test 6-4 UVa439 #include<cstdio> #include<cstring> #include<queue> using na ...

  4. 如何把函数都用promise方式实现?

    如何把函数都用promise方式实现? 我觉得这是一个好问题.当前在我所在的公司,只要用 NodeJS 进行开发,从框架到具体的应用实例到工具,已经全部迁移到以 promise 为中心开发方式.带来的 ...

  5. [Hadoop] - Protocol Buffer安装

    Hadoop从2.x版本开始,底层的RPC远程调用使用ProtocolBuffer格式来传递数据,所以在编译Hadoop的过程中有可能出现提示缺少Protocol服务的异常信息,类似:'protoc ...

  6. C#中运算符的使用

    通过学习知道了知道了运算符的分类及使用方法 运算符用于执行程序代码运算,会针对一个或一个以上操作数项目来进行运算.例如:2+3,其操作数是2和3,而运算符则是“+”. C#语言把除了控制语句和输入输出 ...

  7. MySQL主从复制与主主复制

    1.简介 MySQL作为世界上使用最为广泛的数据库之一,免费是其原因之一.但不可忽略的是它本身的功能的确很强大.随着技术的发展,在实际的生产环境中,由单台MySQL数据库服务器不能满足实际的需求.此时 ...

  8. 《类型编程晋级——shapeless类库使用指南》前言及第一章翻译

    从年初开始进行此项工作,我和合作伙伴包亮付出了大量而艰辛的劳动,现基本翻译完毕,有出版意向,如果有意向欢迎联系,不甚感激!也欢迎各位博友对此翻译提出意见建议以及指导如何出版,在此谢过! 前言 时间回到 ...

  9. java之重定向与转发

    昨天搞了一个问题,关于手机返回按钮的(Android机,ios没有返回键) 在每一步操作都要进过鉴权,如果鉴权不通过就需要跳转到指定jsp页面,再进行link:到app进行登录操作: 然后问题出现了, ...

  10. linux的文件权限小结

    对于初接触Linux的朋友来说,会有各种不习惯和各种昏头,文件的权限就很让人不知所措. ls命令以及字段含义 比如我们列出当前目录文件: 我们来看下上述大致含义: 第1行显示的信息: 总用量(tota ...