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 错误处理
coinitialize和coinitializeex有什么区别?