平時咱們開發中,常常使用Task,後續的.net版本種不少都和Task有關,好比asyn,await有了Task 咱們不多就去關注Thread 了。Task 給咱們帶來了不少的便利之處。是咱們更少的去關注執行的歷程,更多的去關注邏輯。可是有些時候,有些應用。又不得不考慮task 的運行情況,好比這個任務成功與否,是否發生異常。常常聽別人說到task 是在線程池執行的,那咱們今天就來看看task 到底在作什麼了,他執行的時候又作些哪些工做。sql
你們能夠從這裏能夠看到Task 的源代碼,也能夠從reference code 直接download 下來。windows
咱們先來看這段代碼promise
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這個和異步執行的回掉相關,這裏我不在過多說這個,less
接着咱們看到有個字段t_currentTask ,並且是static 的,指向自己的task。你們不知道會不會有疑問,爲何這樣設計呢,其實這樣的設計在.net不少地方都有,好比HttpContext等等,特色基本都會有個Current。這種有點相似單例模式,可是開始已經初始化好,還有個更多的有點你能夠隨時替換,注入你本身的定義的東西。把他看成單例來用也是徹底ok。注意了這裏的訪問修飾符是internal static。異步
接着t_stackGuard,s_taskIdCounter 顧名思義不在過多介紹。ide
下面就是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 一猜也大概直到做用。this
下面又是一個執行過程特別重要的字段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) != 0) { throw new InvalidOperationException(Environment.GetResourceString("Task_Start_Promise")); } if ((options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) != 0) { 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) == 0) ) ? 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 判斷再加上對象的賦值。這個咱們能夠在平時的代碼中加以借用。