Can anyone explain (or have a resource that explains) exactly when ThreadPool threads are released back to the ThreadPool? Here is a small example program (Dotnet fiddle: https://dotnetfiddle.net/XRso3q)
public static async Task Main()
{
Console.WriteLine("Start");
var t1 = ShortWork("SW1");
var t2 = ShortWork("SW2");
await Task.Delay(50);
var t3 = LongWork("LW1");
Console.WriteLine($"After starting LongWork Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.WhenAll(t1, t2);
await t3;
Console.WriteLine("Done");
}
public static async Task ShortWork(string name)
{
Console.WriteLine($"SHORT Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(500);
Console.WriteLine($"SHORT End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
public static async Task LongWork(string name)
{
Console.WriteLine($"LONG Start {name} Thread={Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(2500);
Console.WriteLine($"LONG End {name} Thread={Thread.CurrentThread.ManagedThreadId}");
}
Outputs:
Start
SHORT Start SW1 Thread=1
SHORT Start SW2 Thread=1
LONG Start LW1 Thread=5
After starting LongWork Thread=5
SHORT End SW1 Thread=7
SHORT End SW2 Thread=5
LONG End LW1 Thread=5
Done
Long work starts on thread 5, but at some point thread 5 is released back to the threadpool as thread 5 is able to pick up Short SW1 ending. When exactly does 5 get released back to the threadpool after await Task.Delay(2500)
in LongWork? Does the await
call release it back to the threadpool? I dont think this is the case as if I log the thread id right after the call to LongWork
, that is still running on thread 5. await Task.WhenAll
is called on thread 5 - which then releases control back up to whatever called 'main' - is this where it gets released as there is no 'caller' to go back to?
My understanding of what happens:
- Starts on thread 1, thread 1 executes ShortWork SW1 and SW2.
Task.Delay(50)
is awaited and thread 1 gets released (as there is no more work to do?)- Thread 5 is chosen to pick up the continuation after the 50ms delay
- Thread 5 kicks off
LongWork
, and it it gets to the awaited2500ms
delay. Control gets released back up to main, still on thread 5.t1
andt2
are awaited - control gets released back up to whatever called main (and so thread 5's work is done - it gets released to the threadpool) - At this point no threads are 'doing' anything
- When the ShortWork delay is done, thread 5 and 7 are selected from the pool for the continuation of each call. Once done with the continuation, these are released to the pool (?)
- Another thread picks up the continuation between
Task.WhenAll
andawait t3
, which then immediately gets released because it is just awaitingt3
- A ThreadPool thread is selected to do the continuation of the
LongWork
call - Finally, a ThreadPool thread picks up the last work to write
done
after t3 is done.
Also as a bonus, why does 5 pick up end of SW1, and 7 pick up end of LW1? These are the threads that were just used. Are they somehow kept as 'hot threads and prioritised for continuations that come up?