This is the twentieth fourth part of the .NET Inside Out series. For your convenience you can find other parts in the table of contents in Part 1 – Virtual and non-virtual calls in C#
Let’s take this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System; using System.Threading; using System.Threading.Tasks; public class Program { public static void Main() { Task.Factory.StartNew(Handle); } public static void Handle(){ Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Task.Run(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); }).Wait(); } } |
and compare it with this one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System; using System.Threading; using System.Threading.Tasks; public class Program { public static void Main() { Task.Factory.StartNew(Handle); } public static void Handle(){ Console.WriteLine(Thread.CurrentThread.ManagedThreadId); var tcs = new TaskCompletionSource<bool>(); Task.Run(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); tcs.SetResult(true); }); tcs.Task.Wait(); } } |
They look very similar, however, they give different outputs. First code runs both tasks (Handle
and one sleeping) on the same thread:
1 2 |
11 11 |
while the latter runs on different threads:
1 2 |
10 12 |
Why? That’s because scheduler tries to detect a situation when we are waiting on the task immediately (first code) and run it inline. In the second code this cannot be detected as we wait for “different” task.