避免 Task.Run 导致主线程死锁(C#)
Posted
技术标签:
【中文标题】避免 Task.Run 导致主线程死锁(C#)【英文标题】:Avoiding Task.Run causing deadlock on Main thread (C#) 【发布时间】:2021-08-02 17:05:09 【问题描述】:我相信,虽然不太可能,但使用 Task.Run()
排队的任务有可能最终在主线程上运行。
我担心(在我的 WPF 应用程序中),如果我在此任务中使用 App.Current.Dispatcher.Invoke()
或类似名称,我会导致死锁。
这是一种正当的恐惧吗?如果是这样,有没有办法防止这种情况发生(不检查当前线程*不是*主线程)。
谢谢
【问题讨论】:
【参考方案1】:我相信,虽然不太可能,但使用 Task.Run() 排队的任务有可能最终在主线程上运行。
您错误地认为:这是不可能的。 Task.Run
分派到 ThreadPool,而不是 UI 线程的分派器。两者是完全分开的。
我担心(在我的 WPF 应用程序中),如果我在此任务中使用 App.Current.Dispatcher.Invoke() 或类似方法,我会导致死锁。
无论如何,您都应该避免使用Invoke
,因为存在死锁的风险。风险在于 UI 线程正在等待您的线程做某事,并且通过同步等待 UI 线程有足够的空闲来处理您的消息,您就有死锁的风险。
您通常可以使用 BeginInvoke
代替(拥有一个其进度取决于 UI 正在执行的操作的后台线程通常是不好的设计),但是当您使用 await
和 Progress<T>
/@ 时,您很少需要它987654326@.
【讨论】:
我注意到在 TPL 中使用Parallel.ForEach
通常会在“主”线程上运行一个线程。是的,这个调用阻塞了调用线程,所以使用这个“备用”线程是有意义的。这是一些 TPL 的“魔法”吗?正如 MSDN 所说,它从 ThreadPool
获得分配。
Parallel.ForEach
将使用它被调用的线程,并根据需要加上任意数量的额外线程。如果您从 UI 线程调用它,是的,它将使用 UI 线程。如果你从非 UI 线程调用它,它不会使用 UI 线程。以上是关于避免 Task.Run 导致主线程死锁(C#)的主要内容,如果未能解决你的问题,请参考以下文章