There is a big mistake in your assumption:
When it reaches Task.Delay (5) expectations, thread 2000 returns to thread pool
Since you have not yet waited for foo() when thread 2000 accesses Task.Delay(5) , it simply creates a new Task and returns to testAsync() (to int i = 0; ). It goes into the while block, and only after that you wait for the Task . In this case, if Task is not completed yet, and, expecting the rest of the code to be expected, thread 2000 will return to the thread pool. Otherwise, if Task already completed, it will continue synchronously with foo() (at while (y<5) y++; ).
EDIT:
What if the main method is called testAsync?
When the synchronous method calls and waits for the async method, it should block the thread if the async method returns an incomplete task:
void Main() { var task = foo(); task.Wait();
Please note that in the above case, the thread does not return to the thread pool - it is completely suspended by the OS.
Maybe you can give an example of calling testAsync so that thread 2000 returns to the thread pool?
Assuming thread 2k is the main thread, it cannot return to the thread pool. But you can use Task.Run(()=> foo()) to run foo() in the thread pool, and since the calling thread is the main thread, another thread pool thread will raise this task. So the following code:
static void Main(string[] args) { Console.WriteLine("main started on thread {0}", Thread.CurrentThread.ManagedThreadId); var testAsyncTask = Task.Run(() => testAsync()); testAsyncTask.Wait(); } static async Task testAsync() { Console.WriteLine("testAsync started on thread {0}", Thread.CurrentThread.ManagedThreadId); await Task.Delay(1000); Console.WriteLine("testAsync continued on thread {0}", Thread.CurrentThread.ManagedThreadId); }
The following output was produced (on my PC):
main started on thread 1 testAsync started on thread 3 testAsync continued on thread 4 Press any key to continue . . .
Threads 3 and 4 came and returned to the thread pool.