关于Task的API太多了,网上的实例也很多,现在我们来说说Task究竟是个什么东西【task一般用于多线程,它一定与线程有关】,还有它的返回值有事怎么搞的。
首先我们以一个最简单的API开始,TaskFactory的StartNew<TResult>方法,TaskFactory.cs
public Task<TResult> StartNew<TResult>(Func<Object, TResult> function, Object state) { StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; Task currTask = Task.InternalCurrent; return Task<TResult>.StartNew(currTask, function, state, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask), ref stackMark); } private TaskScheduler GetDefaultScheduler(Task currTask) { if (m_defaultScheduler != null) return m_defaultScheduler; else if ((currTask != null)&& ((currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0)) return currTask.ExecutingTaskScheduler; else return TaskScheduler.Default; }
可见最终和调用Task<TResult>.StartNew等效的,这里的GetDefaultScheduler返回的是TaskScheduler.Default。TaskScheduler.cs实现如下:
public abstract class TaskScheduler { private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler(); public static TaskScheduler Default { get { return s_defaultTaskScheduler; } } internal void InternalQueueTask(Task task) { Contract.Requires(task != null); task.FireTaskScheduledIfNeeded(this); this.QueueTask(task); } }
默认的TaskScheduler.Default是ThreadPoolTaskScheduler实例。现在我们看看Task<TResult>的实现 Future.cs
public class Task<TResult> : Task { internal static Task<TResult> StartNew(Task parent, Func<object, TResult> function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) { if (function == null) { throw new ArgumentNullException("function"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } if ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) { throw new ArgumentOutOfRangeException("creationOptions", Environment.GetResourceString("TaskT_ctor_SelfReplicating")); } // Create and schedule the future. Task<TResult> f = new Task<TResult>(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler, ref stackMark); f.ScheduleAndStart(false); return f; } internal void ScheduleAndStart(bool needsProtection) { Contract.Assert(m_taskScheduler != null, "expected a task scheduler to have been selected"); Contract.Assert((m_stateFlags & TASK_STATE_STARTED) == 0, "task has already started"); // Set the TASK_STATE_STARTED bit if (needsProtection) { if (!MarkStarted()) { // A cancel has snuck in before we could get started. Quietly exit. return; } } else { m_stateFlags |= TASK_STATE_STARTED; } if (s_asyncDebuggingEnabled) { AddToActiveTasks(this); } if (AsyncCausalityTracer.LoggingOn && (Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { //For all other task than TaskContinuations we want to log. TaskContinuations log in their constructor AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task: "+((Delegate)m_action).Method.Name, 0); } try { m_taskScheduler.InternalQueueTask(this); } catch (ThreadAbortException tae) { AddException(tae); FinishThreadAbortedTask(true, false); } catch (Exception e) { TaskSchedulerException tse = new TaskSchedulerException(e); AddException(tse); Finish(false); if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { // m_contingentProperties.m_exceptionsHolder *should* already exist after AddException() Contract.Assert( (m_contingentProperties != null) && (m_contingentProperties.m_exceptionsHolder != null) && (m_contingentProperties.m_exceptionsHolder.ContainsFaultList), "Task.ScheduleAndStart(): Expected m_contingentProperties.m_exceptionsHolder to exist " + "and to have faults recorded."); m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false); } // re-throw the exception wrapped as a TaskSchedulerException. throw tse; } } internal Task( Func<object, TResult> valueSelector, object state, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark) : this(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) { PossiblyCaptureContext(ref stackMark); } internal void PossiblyCaptureContext(ref StackCrawlMark stackMark) { Contract.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null, "Captured an ExecutionContext when one was already captured."); CapturedContext = ExecutionContext.Capture(ref stackMark, ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase); } internal override void InnerInvoke() { // Invoke the delegate Contract.Assert(m_action != null); var func = m_action as Func<TResult>; if (func != null) { m_result = func(); return; } var funcWithState = m_action as Func<object, TResult>; if (funcWithState != null) { m_result = funcWithState(m_stateObject); return; } Contract.Assert(false, "Invalid m_action in Task<TResult>"); } public TResult Result { get { return IsWaitNotificationEnabledOrNotRanToCompletion ? GetResultCore(waitCompletionNotification: true) : m_result; } } }
Task<TResult>的StartNew方法首先调用构造函数,在构造函数里面调用PossiblyCaptureContext方法,PossiblyCaptureContext方法调用ExecutionContext.Capture捕获线程上下文,然后回到StartNew方法,调用Task<TResult>。ScheduleAndStart,ScheduleAndStart方法主要是调用TaskScheduler的InternalQueueTask方法;TaskScheduler的InternalQueueTask方法主要是调用QueueTask,QueueTask方法在子类被覆盖,这里调用ThreadPoolTaskScheduler的QueueTask方法,ThreadPoolTaskScheduler.cs
internal sealed class ThreadPoolTaskScheduler: TaskScheduler { private static readonly ParameterizedThreadStart s_longRunningThreadWork = new ParameterizedThreadStart(LongRunningThreadWork); private static void LongRunningThreadWork(object obj) { Contract.Requires(obj != null, "TaskScheduler.LongRunningThreadWork: obj is null"); Task t = obj as Task; Contract.Assert(t != null, "TaskScheduler.LongRunningThreadWork: t is null"); t.ExecuteEntry(false); } protected internal override void QueueTask(Task task) { if ((task.Options & TaskCreationOptions.LongRunning) != 0) { // Run LongRunning tasks on their own dedicated thread. Thread thread = new Thread(s_longRunningThreadWork); thread.IsBackground = true; // Keep this thread from blocking process shutdown thread.Start(task); } else { // Normal handling for non-LongRunning tasks. bool forceToGlobalQueue = ((task.Options & TaskCreationOptions.PreferFairness) != 0); ThreadPool.UnsafeQueueCustomWorkItem(task, forceToGlobalQueue); } } }
如果Task是TaskCreationOptions.LongRunning,那么我们新建一个逻辑线程来运行当前的Task,否者放到线程池里面运行。
单独的逻辑线程调用s_longRunningThreadWork回调方法【该方法调用task的ExecuteEntry】;如果是线程池那么我们调用Task的ExecuteWorkItem方法【其实还是调用Task的ExecuteEntry】,Task.cs
public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable { [ThreadStatic] internal static Task t_currentTask;