CoInitialize() 是不是总是在每个 .Net Framework / .Net Core 线程上隐式调用?

Posted

技术标签:

【中文标题】CoInitialize() 是不是总是在每个 .Net Framework / .Net Core 线程上隐式调用?【英文标题】:Is CoInitialize() always implicitly called on every .Net Framework / .Net Core thread?CoInitialize() 是否总是在每个 .Net Framework / .Net Core 线程上隐式调用? 【发布时间】:2022-01-04 14:57:32 【问题描述】:

[MTAThread][STAThread] 属性控制.Net 应用程序中COM 的单元线程模型,并且根据我自己的(非常有限的)测试,CoInitializeEx() 返回1 (S_FALSE) 如果从控制台 C# 应用程序的主线程调用。

根据 Microsoft 文档,S_FALSE 表示“COM 库已在此线程上初始化”。

我想知道的是,框架本身是否真的有合同保证 COM 将在每个 .Net(框架或核心应用程序)线程上初始化?

如果是这样,是否也保证所有线程都将使用相同的(STA 或 MTA)模型进行初始化?

我问这个是因为对于 DirectShow 应用程序来说,COM 在每个线程上初始化是至关重要的,我想避免在代码中重复调用 CoInitializeEx()CoUnitialize()框架。

【问题讨论】:

显然不能保证所有核心应用程序都可以运行,因为它们实际上不会在甚至知道 COM 是什么的系统上运行。但我假设您将自己限制在 Windows 上运行的 .NET 应用程序上。 线程池线程是 MTA,因为它们必须为任何事情做好准备。您自己的入口点应该用适当的属性标记,并且您显式创建的任何线程都可以在开始之前设置单元状态。我不确定您还需要考虑哪些其他线程需要一些默认值。 Some hints of documentation about this on Old New Thing。不幸的是,引用的任何文档都没有链接到任何帖子 你不喜欢麻烦。使用 Thread.SetApartmentState()。到目前为止,最好的方法是确保它无关紧要,不要从另一个线程进行调用,你永远不必担心线程安全。如果由于某种原因这是不可避免的,那么使用 .NET 的机制来编组调用。 Example. how to change default model for threads? 在启动线程之前,您必须使用较低级别的Thread 类并调用Thread.SetApartmentState()。注意:这不是线程池线程。 【参考方案1】:

文档指出threads from the Managed Thread Pool 是

在多线程单元中

documentation for Task.Run() 也声明了它

将指定的工作排入队列以在 ThreadPool 上运行

ThreadPool 在这种情况下是托管线程池。)

最后,the documentation for class Thread's obsolete ApartmentState property 声明

在 .NET Framework 2.0 版中,新线程被初始化为 ApartmentState.MTA 如果之前没有设置他们的公寓状态 它们已启动。

这几乎涵盖了创建线程的所有托管方式。

您当然也可以在 Main() 方法上添加 [MTAThread] 属性,但即使这样也没有必要,因为主入口点的默认值也是 MTA。

因此,归根结底 - 除非您调用任何不寻常的第三方代码,否则您几乎可以保证您的线程将是 MTA。

【讨论】:

以上是关于CoInitialize() 是不是总是在每个 .Net Framework / .Net Core 线程上隐式调用?的主要内容,如果未能解决你的问题,请参考以下文章

OTL TOmniBlockingCollection(COM 多线程)中的 CoInitialize/CoUninitialize 错误处理

Qt-不调用CoInitialize-实现SDL多线程运行

Qt-不调用CoInitialize-实现SDL多线程运行

coinitialize和coinitializeex有什么区别?

Qt 在线程中使用QCamera以及ffmpeg进行视频流推送出现(尚未调用 CoInitialize) 解决办法

多线程调用COM组件的体会(CoInitialize)(转)