简体   繁体   中英

Thread blocked after await

With this code:

    static void Main(string[] args)
    {
        Console.WriteLine("Main Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
        Task.Run(() => AsyncMethod()).Wait();
        Console.WriteLine("Main Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
        Console.ReadKey();
    }

    static async Task AsyncMethod()
    {
        Console.WriteLine("AsyncMethod Thread Pre - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
        await Task.Delay(4000).ConfigureAwait(false);
        Console.WriteLine("AsyncMethod Thread Post - " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
    }

The output is:

Main Thread Pre - 8652
AsyncMethod Thread Pre - 4764
AsyncMethod Thread Post - 1768
Main Thread Post - 8652

Using the Concurrency Visualizer, I can see that during the 4 second delay, thread 4764 is stuck in Synchronization. It is eventually unblocked by the main thread on shutdown.

Shouldn't thread 4764 be returned to the ThreadPool once it hits the await ? (That being said I don't know what that would look like inside the Concurrency Visualizer)

Shouldn't thread 4764 be returned to the ThreadPool once it hits the await?

Yes. And it is.

(That being said I don't know what that would look like inside the Concurrency Visualizer)

That's easy enough to check. Just explicitly execute some code in the thread pool, and take a look at what that thread looks like in the visualizer when it's not busy.

For example:

ThreadPool.QueueUserWorkItem(o =>
    {
        Console.WriteLine("worker: " + GetNativeThreadId(System.Threading.Thread.CurrentThread));
        Thread.Sleep(250);
    });

(I added the sleep so it shows up more easily in the visualizer as having done something :) ).

And when you do, you'll see that what it looks like is just like what you see. :)


When I ran this, the thread pool even used the same worker thread that it used for the original Task . And you can see that a thread pool worker thread sits in the Synchronization state while it's waiting for more work.

Which makes sense. At an abstract level, what's the thread pool doing? The whole point is for it to have threads which already exist. But you don't want those threads actually out there working unless they have something to work on. That would burn CPU time for no reason. So instead, they wait on a synchronization object.

When something (like Task ) wants to use one, it queues a work item, and then the thread pool signals to the thread it's got something to do. This wakes up the thread, it does its work, and then it blocks on the synchronization object again, waiting for something else to do.

If you check the call stack for the relevant threads, you'll see the worker thread waiting on a call to WaitForSingleObject() , and you'll see that the thread pool ultimately unblocks the thread using ReleaseSemaphore() .

And this shows up as the Synchronization state for the thread pool thread, just as you saw.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM