C# Task 是什么?返回值如何实现? Wait如何实现

本文深入探讨C#中的Task,解析Task的创建、返回值设定及Wait实现过程。从TaskFactory.StartNew到Task<TResult>.StartNew,再到TaskScheduler的调度,详细阐述Task在线程池中的执行以及Task的生命周期,包括如何捕获线程上下文、执行回调、设置返回值,并在任务完成后触发完成状态更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于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; 
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值