等待后线程被阻塞

时间:2015-04-22 16:08:31

标签: c# multithreading async-await

使用此代码:

    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));
    }

输出结果为:

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

使用Concurrency Visualizer,我可以看到在4秒延迟期间,线程4764卡在同步中。它最终在关机时被主线程解锁。

线程4764一旦到达ThreadPool,是否应该返回await? (据说我不知道​​在Concurrency Visualizer中会是什么样子)

1 个答案:

答案 0 :(得分:4)

  

一旦线程4764到达等待点,它是否应该返回到ThreadPool?

是。它就是。

  

(据说我不知道​​在Concurrency Visualizer中会是什么样子)

这很容易检查。只需在线程池中显式执行一些代码,并在可视化器不忙时查看该线程的样子。

例如:

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

(我添加了睡眠,因此它在可视化工具中更容易显示为做了一些事情:))。

当你这样做时,你会发现它看起来就像你所看到的一样。 :)


当我运行它时,线程池甚至使用了与原始Task相同的工作线程。并且您可以看到线程池工作线程在等待更多工作时处于Synchronization状态。

哪个有道理。在抽象层面,线程池的作用是什么?重点是它拥有已经存在的线程。但是你不希望那些线程实际上在那里工作,除非他们有一些工作要做。这会毫无理由地燃烧CPU时间。因此,他们等待同步对象。

当某些内容(如Task)想要使用一个时,它会将一个工作项排队,然后线程池向该线程发出信号,表明它有事可做。这会唤醒线程,它会完成它的工作,然后再次阻塞同步对象,等待其他事情去做。

如果检查相关线程的调用堆栈,您将看到工作线程正在等待对WaitForSingleObject()的调用,并且您将看到线程池最终取消阻塞线程使用ReleaseSemaphore()

正如您所见,这显示为线程池线程的Synchronization状态。