我們昨天聊到要透過解析 threadPool 檔案中的 FinishContinuations
method 來了解 .Net 框架中 threadPool 的樣貌以及使用。而FinishContinuations
會在特定階段被 Task 調用。
資料來源 : https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,dadbf616e42976ee
internal void FinishContinuations()
{
// 設定目前執行任務完成, 因為此函數會在 Task 完成其任務時被調用
object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel);
TplEtwProvider.Log.RunningContinuation(Id, continuationObject);
// 在 WhenAll 提過, 當別的物件要把某個任務放到某個任務後面執行時, 就會將那個任務加入到 連續任務區
// 當連續任務區為空, 此任務結束。
if (continuationObject != null)
{
// 連續任務區不為空要執行以下這段
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, this.Id, CausalitySynchronousWork.CompletionNotification);
// Skip synchronous execution of continuations if this task's thread was aborted
bool bCanInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) ||
(Thread.CurrentThread.ThreadState == ThreadState.AbortRequested) ||
((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0));
// 若是連續任務區只有一個 Action 就直接執行或送入排程(這個 method 有點東西, 目前不能細說)
Action singleAction = continuationObject as Action;
if (singleAction != null)
{
AwaitTaskContinuation.RunOrScheduleAction(singleAction, bCanInlineContinuations, ref t_currentTask);
LogFinishCompletionNotification();
return;
}
// Handle the single-ITaskCompletionAction case
ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
if (singleTaskCompletionAction != null)
{
// 可以接著執行
if (bCanInlineContinuations)
{
// 直接用同一個 Task 接著執行這個任務
singleTaskCompletionAction.Invoke(this);
}
else
{
// 不能用同一個 task 接著執行, 把 Task 打包加入 TP
ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
}
LogFinishCompletionNotification();
return;
}
// 此段流程和上一段很像, 略。
TaskContinuation singleTaskContinuation = continuationObject as TaskContinuation;
if (singleTaskContinuation != null)
{
singleTaskContinuation.Run(this, bCanInlineContinuations);
LogFinishCompletionNotification();
return;
}
// Not a single; attempt to cast as list
List<object> continuations = continuationObject as List<object>;
// 連續任務為空
if (continuations == null)
{
LogFinishCompletionNotification();
return; // Not a single or a list; just return
}
//
// Begin processing of continuation list
//
// 此段是在處理, 連續任務區 有多個任務時的狀況, 略, 明天聊
}
}
可以發現以下流程
此外, 連續任務若有多個任務, 有另一套處理程序。
可以在同一個 Thread 接著執行的評斷標準之後也會聊到。
雖然只有一個連續任務看起來有三種處理的 CASE , 但究其本質都是差不多的。
明天我們針對 ITaskCompletionAction
這個 CASE 往下,
要看
singleTaskCompletionAction.Invoke(this);
和
ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
為何一個可以使原來的 Task 接著執行連續任務, 另一個可以 把 task 送入 TP 給別人執行。
今天因為篇幅問題, 沒有聊到 TP , 所以明天就繼續寫, 看能不能把上面那兩個 method 聊完。
明天見!