Ian*_*oyd 12 .net com multithreading
我知道每个线程在与COM系统交互之前调用COM 的要求CoInitialize.
.NET公开了一些内部在线程上运行的项目,例如:
ThreadPool 线程BackgroundWorker class(使用异步委托(使用线程池线程))如果我要从一个线程与一个COM对象进行交互,我是否需要先调用CoInitialize?
我问,因为可能会有更多魔法自动称呼它 - 我不知道.
托管和非托管线程
对于互操作性,公共语言运行库在调用COM对象时创建并初始化公寓.托管线程可以创建并进入仅包含一个线程的单线程单元(STA),或包含一个或多个线程的多线程单元(MTA).当COM公寓和线程生成的公寓兼容时,COM允许调用线程直接调用COM对象.如果公寓不兼容,COM会创建一个兼容的公寓,并通过新公寓的代理人打电话.
运行时调用CoInitializeEx将COM单元初始化为MTA或STA单元.
更新二:
看起来你不应该使用.NET提供的任何类型的线程中的COM:
托管线程池
有几种情况适合创建和管理自己的线程而不是使用线程池线程:
您需要前台线程.
您需要一个线程具有特定的优先级.
您有任务导致线程长时间阻塞.线程池具有最大线程数,因此大量被阻塞的线程池线程可能会阻止任务启动.
您需要将线程放入单线程单元中.所有ThreadPool线程都在多线程单元中.
您需要具有与线程关联的稳定标识,或者将线程专用于任务.
更新三:
看起来您可以设置非线程线程的线程模型:
Microsoft Windows中的托管和非托管线程
可以标记托管线程以指示它将托管单线程或多线程单元.Thread类的GetApartmentState,SetApartmentState和TrySetApartmentState方法返回并分配线程的单元状态.如果尚未设置状态,则GetApartmentState将返回ApartmentState.Unknown.
仅当线程处于ThreadState.Unstarted状态时才能设置该属性; 它只能为一个线程设置一次.
如果在线程启动之前未设置单元状态,则将线程初始化为多线程单元(MTA).
很多相互矛盾的信息.
这就是为什么我们会使用Stackoverflow上的任何人说的真正答案.
Bre*_*McK 10
这里的信息实际上并没有冲突 - 如果你是COM的新手,那就不一定非常清楚了.
简短回答:
[STAThread]属性以Main()请求运行时将主线程初始化为STA,或者在调用之前在您创建的新线程上使用thread.SetApartmentState(ApartmentState.STA)thread.Start() - 否则它们是MTA by默认.在任何情况下,一旦线程启动并运行,就无法修改线程单元模型.较长的回答:有两种方法来调用CoInitialize - 你可以用它来初始化线程作为单线程单元线程(STA),或作为多线程单元的线程(MTA).上面的文字说的是默认情况下,新线程和线程池线程自动被预先CoInitialized为MTA-flavor.但是使用新线程,如果在实际启动线程之前执行此操作,则可以使用ApartmentState来指定STA风格.无论如何,它始终以一种方式或另一种方式进行初始化.
请注意,基于UI的程序上的Main()标有[STAThread]属性,以确保它是基于STA的; 在控制台应用程序上,缺少[STAThread]意味着它被作为MTA CoInited.这样做的原因属性,顺便说一句,就是调用Main()方法的线程是一个线程使用的ApartmentState不能指定STA VS MTA - 因为它已经运行,并通过时间的Main()执行,所以来不及用那个; 所以将属性视为运行时提示在调用Main()之前设置单元状态.
需要注意的关键是STA通常与UI一起使用,需要一个消息循环(.Net WinForms为您提供); STA代码永远不应该使用Sleep()或类似代码阻止,否则您的UI也会阻塞.另一方面,MTA是为工作人员使用而设计的 - 例如,后台任务,下载文件或在后台进行计算,通常不应该拥有UI.您可以使用其中任何一个的COM,但这可能取决于COM对象正在做什么或从哪里获得它.如果它是一个UI组件,可能你想从STA线程中使用它; 另一方面,如果它是用于下载或进行计算的组件,则通常在MTA线程中使用它.
上面的更新1基本上是说.Net运行时总是为你调用CoInitialize - 但是让你选择STA vs MTA,MTA是默认值.
上面的更新2基本上是说因为ThreadPool线程是MTA(并且你不能改变它),所以你应该只使用它们来进行后台操作,而不是将它们用于UI任务.
更新3说,对于新线程,您可以选择MTA与STA - 与更新1相同,只是更明确地了解API.
整个MTA与STA之间的关系可能非常复杂,建议将本文作为起点.不过,大局主要通过记住STA =单线程和UI来总结; MTA =多个线程,后台/工作人员任务.(STA vs MTA也适用于对象,而不仅仅是线程,COM在幕后做了大量工作,让不同类型的线程使用不同类型的对象.当它运行良好时,你没有意识到它和可以幸福地忽略它;但是当你遇到限制或限制时,弄清楚发生了什么通常很棘手.)