我認為不應計劃、運行使用已取消令牌的 Task.Factory.StartNew 初始化的任務,并且應以已取消狀態結束。但是在 .NET 5 上的 VS 2019 中,我很偶然地注意到,很少有任務處于運行狀態。
在這種情況下,任務內部的操作顯然沒有執行。因為在我的示例中 1 沒有輸出到控制臺。誰能解釋實際發生的事情?
問題。為什么這個示例中的任務有時會處于運行狀態,雖然它顯然不起作用?
升級版。在 .NET 6 上檢查了 VS 2022。同樣的事情。


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}");
}
}
}
uj5u.com熱心網友回復:
在我的機器上Running,無論是使用 Framework 4.7.2 還是使用 .NET 6(VS 2019),您的代碼都不會達到狀態。正如@JonasH 建議的那樣,我查看了代碼。以下是一種可能的解釋。
在下面的代碼中,在任務計劃運行后由(此處為)ExecuteEntryUnsafe呼叫。我嘗試了一個基本的自定義調度程式,在這種情況下,呼叫的方法帶有一些額外的安全性以防止雙重呼叫。但解釋仍然有效。免責宣告:我與斯蒂芬·克利里(Stephen Cleary)這樣的人的聲譽或知識相去甚遠,因此請謹慎回答。如果這不正確,我將洗掉它。TaskSchedulerThreadPoolTaskSchedulerExecuteEntry()
//---------
// 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();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/457410.html
下一篇:MySQL事務提交流程詳解
