与 new Task(action, token) 结合时,Action 中的参数如何填充

How does the parameter in an Action get filled when combined with new Task(action, token)

简介 首先,我已经阅读了以下文章,但我认为它们没有回答这个问题:

Cancellation token in Task constructor: why? What is the use of passing CancellationToken to Task Class constructor?

我很清楚token参数的用途。

我的问题 我尝试用内联注释记录代码,让您了解我在哪里遗漏了所有链接。

代码完成了我想要它做的事情: - 每 2 秒写入一次控制台 - 10 秒后停止

我的问题:"howDoIGetFilled"参数如何获取"token"参数的值。第二个参数用于 Task 实例本身,而不是正在使用的 Action。 如果有任何不清楚的地方,请让我知道你想澄清什么。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDelegatePlayground
{
    class Program
    {
        static void Main(string[] args)
        {           
            var source = new CancellationTokenSource();
            var token = source.Token;

            Action<object> action = howDoIGetFilled => TestCancellationWithToken((CancellationToken)howDoIGetFilled);
            //I understand that this works, as you pass in the token and it gets passed to the "howDoIGetFilled" variable.
            //action(token);        
            //Wrong because it's "hardcoding" the token variable now but I don't understand how the above gets filled in.
            //Action<object> action = howDoIGetFilled => TestCancellationWithToken(token);
            var task = new Task(action, token);

            task.Start();
            Thread.Sleep(10000);

            //This should cancel the operation       
            Console.WriteLine("Cancelling");                 
            source.Cancel();

            Console.WriteLine("Ended, press any key to close the application.");
            Console.ReadKey();           
        }

        public static void TestCancellationWithToken(CancellationToken token)
        {
            //no intellisense here for token / source            
            while (true)
            {
                if (token.IsCancellationRequested)
                    break;

                Console.WriteLine("test");                     
                Thread.Sleep(2000);
            }
        }
    }
}

简答:

当在线程池中调用 Task 时,将执行操作,并且根据它是 Action 还是 Action<T>,将在有或没有 [=14] 的情况下执行=] 你可以选择传入。

长答案:

正在寻找 Taskreference source,这是它被调用的方式:

    /// <summary>
    /// The actual code which invokes the body of the task. This can be overriden in derived types.
    /// </summary>
    internal virtual void InnerInvoke()
    {
        // Invoke the delegate
        Contract.Assert(m_action != null, "Null action in InnerInvoke()");
        var action = m_action as Action;
        if (action != null)
        {
            action();
            return;
        }
        var actionWithState = m_action as Action<object>;
        if (actionWithState != null)
        {
            actionWithState(m_stateObject);
            return;
        }
        Contract.Assert(false, "Invalid m_action in Task");
    }

您可以在参考源中四处单击以找到您的 CancellationTokenaction 的路径。

但基本上,构造函数调用一个内部构造函数,该构造函数又调用一个 TaskConstructorCore,它设置 m_stateObjectm_action(两者都可以在操作时使用被称为)。

InnerInvoke() 由在多个地方调用的方法 Execute() 调用,但您明白了。

我找到了Execute的路由,它来自执行工作项的线程池。

    /// <summary>
    /// IThreadPoolWorkItem override, which is the entry function for this task when the TP scheduler decides to run it.
    /// 
    /// </summary>
    [SecurityCritical]
    void IThreadPoolWorkItem.ExecuteWorkItem()
    {
        ExecuteEntry(false);
    }

有趣的是,如果在任务排队之前取消令牌已经取消,则会出现短路。