Task有一个 TaskStatus类型 的实例属性Status,指示当前Task实例是何状态。
另外要注意,Task是一个链表的结构,记住这个链表,有助对Task进一步理解。
另外,task实例默认的m_taskScheduler(TaskScheduler类型)属性是
new ThreadPoolTaskScheduler();。m_taskScheduler就是用来为Task做调度服务的。
1 “正常”执行一个Task
Created-WaitingToRun-Running-RanToCompletion
var sw = new Stopwatch();
var myTask = new Task(() => {
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms myTask started");
Thread.Sleep(TimeSpan.FromSeconds(3));
});
var statFlg = (TaskStatus)(-1);
sw.Start();
Task.Run(() =>
{
while (true)
{
if (statFlg != myTask.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask),-12} Status: {myTask.Status,-12}");
statFlg=myTask.Status;
}
}
});
Thread.Sleep(TimeSpan.FromSeconds(1));
myTask.Start();
执行结果
这里的myTask经历了Created、WaitingToRun、Running、RanToCompletion,4个状态。图中可以看到WaitingToRun转到Running并没有代码做显示状态切换,两个状态的时间间隔约 7 毫秒,相对较短。如果是Task.Run(()=>{});,那Created、WaitingToRun、Running三个状态凑到了一起,按顺序“立马”执行。
2 两个任务,并抛异常
WaitingForActivation,Faulted
var sw = new Stopwatch();
var myTask = new Task(() => {
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms myTask started");
Thread.Sleep(TimeSpan.FromSeconds(3));
});
var myTask2 = myTask.ContinueWith(tt => {
Thread.Sleep(TimeSpan.FromSeconds(3));
throw new Exception();
});
var statFlg = (TaskStatus)(-1);
var statFlg2 = (TaskStatus)(-1);
sw.Start();
Task.Run(() =>
{
while (true)
{
if (statFlg != myTask.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask),-12} Status: {myTask.Status,-12}");
statFlg=myTask.Status;
}
}
});
Task.Run(() =>
{
while (true)
{
if (statFlg2 != myTask2.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask2),-12} Status: {myTask2.Status,-12}");
statFlg2 = myTask2.Status;
}
}
});
Thread.Sleep(TimeSpan.FromSeconds(1));
myTask.Start();
myTask2通过ContinueWith的防止追加到myTask之后,myTask开启,myTask2是WaitingFroActivation的状态了。task内抛出异常,则任务就被置为错误状态。
3 取消执行
Canceled
var tokenSource=new CancellationTokenSource();
var sw = new Stopwatch();
var myTask = new Task(() => {
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms myTask started");
while (true)
{
tokenSource.Token.ThrowIfCancellationRequested();
}
//throw new Exception();
}, tokenSource.Token);
var myTask2 = myTask.ContinueWith(tt => {
Thread.Sleep(TimeSpan.FromSeconds(3));
throw new Exception();
});
var statFlg = (TaskStatus)(-1);
var statFlg2 = (TaskStatus)(-1);
sw.Start();
Task.Run(() =>
{
while (true)
{
if (statFlg != myTask.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask),-12} Status: {myTask.Status,-12}");
statFlg=myTask.Status;
}
}
});
Task.Run(() =>
{
while (true)
{
if (statFlg2 != myTask2.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask2),-12} Status: {myTask2.Status,-12}");
statFlg2 = myTask2.Status;
}
}
});
Thread.Sleep(TimeSpan.FromSeconds(1));
myTask.Start();
Thread.Sleep(TimeSpan.FromSeconds(3));
tokenSource.Cancel();
要注意这里,
tokenSource.Token.ThrowIfCancellationRequested();这样是取消线程操作,如果直接在任务里throw的话,那myTask就会被置为Fault。不过无论是那种方式停止myTask,ContinueWith的下一下线程都是会继续执行的。
4 等待子任务完成
WaitingForChildrenToComplete
var tokenSource=new CancellationTokenSource();
var sw = new Stopwatch();
var myTask = new Task(() => {
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms myTask started");
Task.Factory.StartNew(() =>
{
Console.WriteLine($"{currentTime,12}ms In sub task.");
Thread.Sleep(TimeSpan.FromSeconds(7));
}, TaskCreationOptions.AttachedToParent);
}, tokenSource.Token);
var myTask2 = myTask.ContinueWith(tt => {
Thread.Sleep(TimeSpan.FromSeconds(3));
throw new Exception();
});
var statFlg = (TaskStatus)(-1);
var statFlg2 = (TaskStatus)(-1);
sw.Start();
Task.Run(() =>
{
while (true)
{
if (statFlg != myTask.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask),-12} Status: {myTask.Status,-12}");
statFlg=myTask.Status;
}
}
});
Task.Run(() =>
{
while (true)
{
if (statFlg2 != myTask2.Status)
{
var currentTime = sw.ElapsedMilliseconds;
Console.WriteLine($"{currentTime,12}ms Task Name: {nameof(myTask2),-12} Status: {myTask2.Status,-12}");
statFlg2 = myTask2.Status;
}
}
});
Thread.Sleep(TimeSpan.FromSeconds(1));
myTask.Start();
Thread.Sleep(TimeSpan.FromSeconds(3));
tokenSource.Cancel();
WaitingForChildrenToComplete状态的切换可能并不是和子线程执行状态那么同步。