为什么 Task.Delay 会破坏线程的 STA 状态?

介绍

这是一个很长的问题!您会在开始时找到有关该问题的一些背景知识,然后是代码示例,这些示例已针对表示形式进行了简化,然后是问题。请按照您认为适合您的任何顺序阅读!

背景资料

我正在为与 STA COM 通信的应用程序编写概念验证部分。这部分应用程序需要在单线程单元 (STA) 上下文中运行,以便与所述 STA COM 通信。应用程序的其余部分在 MTA 上下文中运行。

当前状态

到目前为止我想出的是创建一个包含循环的通信类,在 STA 中运行。while需要中继到 COM 对象的工作从外部排队到CommunicationConcurrentQueue。然后工作项在 while 循环中出列并执行工作。

代码上下文

交流类

这是一个static类,包含一个旨在在 STA 状态下运行并检查是否需要由 COM 完成某些工作并将工作分派给处理程序的循环。


心有法竹
浏览 177回答 2
2回答

大话西游666

汉斯做到了。SynchronizationContext 从技术上讲await,您的代码正在中断,因为. 但即使你写了一个,也不够。这种方法的一个大问题是您的 STA 线程没有启动。STA 线程必须抽取 Win32 消息队列,否则它们就不是 STA 线程。SetApartmentState(ApartmentState.STA)只是告诉运行时这是一个 STA 线程;它不会使其成为 STA 线程。您必须泵送消息才能使其成为 STA 线程。您可以自己编写消息泵,但我不知道有谁敢这样做。大多数人从WinForms(la Hans 的回答)或WPF安装消息泵。也可以使用UWP 消息泵来执行此操作。使用提供的消息泵的一个很好的副作用是它们还提供一个SynchronizationContext(例如WinFormsSynchronizationContext/ DispatcherSynchronizationContext),因此await可以自然地工作。此外,由于每个 .NET UI 框架都定义了一个“运行此委托”的 Win32 消息,因此底层 Win32 消息队列也可以包含您想要排队到您的线程的所有工作,因此显式队列及其“运行程序”代码不再是必要的。

湖上湖

因为在await Task.Delay()语句之后,您的代码在 ThreadPool 线程之一内运行,并且由于 ThreadPool 线程在设计上是 MTA。var th = new Thread(async () =>        {            var beforAwait = Thread.CurrentThread.GetApartmentState(); // ==> STA              await Task.Delay(1000);            var afterAwait = Thread.CurrentThread.GetApartmentState(); // ==> MTA        });        th.SetApartmentState(ApartmentState.STA);        th.Start();
打开App,查看更多内容
随时随地看视频慕课网APP