首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >已取消令牌的Task.Factory.StartNew的状态正在运行

已取消令牌的Task.Factory.StartNew的状态正在运行
EN

Stack Overflow用户
提问于 2022-03-31 06:50:20
回答 1查看 101关注 0票数 0

我认为使用Task.Factory.StartNew初始化的带有已取消令牌的任务不应该被调度、运行,并且应该以已取消的状态结束。但是,在.NET 5上的VS 2019年中,我注意到很少有任务具有运行状态。

在这种情况下,显然没有执行任务内部的操作。因为在我的示例中,1没有输出到控制台。有人能解释一下到底发生了什么吗?

问题.为什么这个例子中的任务有时运行状态,尽管它显然不工作?

UPD.在.NET 6上查看VS 2022,也是一样的。

代码语言:javascript
复制
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(1);
            Thread.Sleep(100);

            Task t1 = new Task(() => { }, cancellationTokenSource.Token);
            Task t2 = new Task(() => { }, cancellationTokenSource.Token);
            Task t3 = new Task(() => { }, cancellationTokenSource.Token);
            Task t4 = new Task(() => { }, cancellationTokenSource.Token);
            Task t5 = new Task(() => { }, cancellationTokenSource.Token);           
           
            Console.WriteLine($"t1: {t1.Status}");
            Console.WriteLine($"t2: {t2.Status}");
            Console.WriteLine($"t3: {t3.Status}");
            Console.WriteLine($"t4: {t4.Status}");
            Console.WriteLine($"t5: {t5.Status}");

            Task t6 = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Console.WriteLine(1);
                }

            }, cancellationTokenSource.Token);

            Console.WriteLine($"t6: {t6.Status}");
            Console.WriteLine($"t6: {t6.Status}");
            Console.WriteLine($"t6: {t6.Status}");
            Console.WriteLine($"t6: {t6.Status}");
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-31 14:13:28

在我的机器上,您的代码从未达到Running状态,无论是Framework4.7.2还是.NET 6 (VS 2019)都是如此。正如@JonasH建议的那样,我看了一下代码。下面是一个可能的解释。

在下面的代码中,ExecuteEntryUnsafeTaskScheduler (这里是ThreadPoolTaskScheduler)在任务计划运行后调用。我尝试使用一个基本的自定义调度程序,在这种情况下,调用的方法是带有一些附加安全性的ExecuteEntry(),以防止双重调用。但这一解释仍然有效。

免责声明:我远没有像Stephen这样的人的名声和知识,所以请谨慎地接受这个答案。如果这不对,我就把它删除。

代码语言:javascript
复制
//---------
// Task.cs
//---------

internal void ExecuteEntryUnsafe(Thread? threadPoolThread)
{
    // [SOURCE comment] Remember that we started running the task delegate
    // This is what actually makes the status show as Running (see source):
    // ...
    // int sf = m_stateFlags;
    // 
    // if ((sf & TASK_STATE_FAULTED) != 0) rval = TaskStatus.Faulted;
    // else if ((sf & TASK_STATE_CANCELED) != 0) rval = TaskStatus.Canceled;
    // else if ((sf & TASK_STATE_RAN_TO_COMPLETION) != 0) rval = TaskStatus.RanToCompletion;
    // else if ((sf & TASK_STATE_WAITING_ON_CHILDREN) != 0) rval = TaskStatus.WaitingForChildrenToComplete;
    // else if ((sf & TASK_STATE_DELEGATE_INVOKED) != 0) rval = TaskStatus.Running; <-- here
    // ...

    m_stateFlags |= (int)TaskStateFlags.DelegateInvoked;

    // *** 
    // On your machine, execution probably switches back to main thread for a fraction of a second here.
    // Hence one of your WriteLines outputs "Running". But this means "delegate was invoked", not necessarily "code is executing".
    // On my machine this does not happen, so I do not see Running status.
    // *** 

    if (!IsCancellationRequested & !IsCanceled)
    {
        ExecuteWithThreadLocal(ref t_currentTask, threadPoolThread);
    }
    else
    {
        // As Cancellation is requested this will be executed, even if IsCancelled is false.
        ExecuteEntryCancellationRequestedOrCanceled(); 
    }
}

// ...

internal void ExecuteEntryCancellationRequestedOrCanceled()
{
    // If Task is cancelled; this is different that "is cancellation requested". So this block is executed.
    if (!IsCanceled) 
    {
        // Set Cancelled flag.
        int prevState = Interlocked.Exchange(ref m_stateFlags, m_stateFlags | (int)TaskStateFlags.Canceled);

        // If previous state was not yet Cancelled, perform some cleanup.
        if ((prevState & (int)TaskStateFlags.Canceled) == 0)
        {
            CancellationCleanupLogic();
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71688073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档