C#应用程序过程中的COM线程套间(STA,MTA)管理

时间:2019-03-29 13:33:57

标签: c# multithreading sta mta

我试图了解C#线程套间并有疑问:

  1. 公寓到底是什么,包含什么?

  2. The Apartment and the COM Threading Architecture

      

    一个进程可以具有零个或多个单线程单元以及零个或一个多线程单元。

    有人可以为应用提供C#代码示例示例或说明吗?

    1. 0个STA,0个MTA
    2. 1个STA,0个MTA
    3. 2个STA,0个MTA
    4. 0个STA,1个MTA
    5. 1个STA,1个MTA
    6. 2个STA,1个MTA

什么时候应该使用每种情况?

1 个答案:

答案 0 :(得分:1)

  1. COM公寓是一个逻辑概念。公寓包含线程。 STA公寓只能包含一个线程(因此名称为“单线程公寓”)。一个MTA可以包含多个线程(因此称为“多线程单元”)。由于MTA可以包含任意数量的线程,因此一个进程中最多有一个MTA。

  2. 您可以轻松地自己编写这些样本。只需使用C#创建线程,然后在线程入口点方法的开头调用Thread.SetApartmentState。您设置为MTA的任何线程都将驻留在单个MTA中。您设置为STA的任何线程都将各自驻留在自己的STA中。

不要试图摆弄线程池线程的驻留状态。这些线程是共享的(它是一个池),因此尝试更改它们的工作方式并不好。另外,线程一旦属于一个单元,就无法更改。

哦,我几乎忘了回答“何时/应该使用每种情况”:永远,如果可以的话。

即使在编写COM对象时,我也总是更喜欢编写“自由线程”对象(它们不在乎它们位于什么单元中),但是我可以这样做,因为我具有理解线程和线程的超能力。知道如何使用互斥锁。之所以创建线程模型,是因为(或至少部分是因为)许多早期的准专业VB开发人员不了解这些概念(也许还是不明白?),因此COM员工试图提出一种仍然可以使他们很容易做些棘手的事情。

因此,当您尝试将COM对象从一间公寓传递到另一间公寓时,会发生什么事情,那就是它必须经过特殊的(讨厌的)魔术才能封送;甚至从一间公寓打电话到另一间公寓都必须经过特殊的(烦人的)魔术。这是有关代理和存根的所有爵士乐出现的地方。如果您想学习所有这些东西的工作原理,那么……您知道文档的位置。但是,如果由于某种原因而不必使用它(例如与现有COM对象互操作),则尽可能避免使用它。

评论中的其他问题:

  

我们可以为线程设置单元,对线程使用Thread.SetApartmentState或对方法使用[STA \ MTAThread]属性。但是我们可以为对象设置公寓吗?

不。一个COM对象属于在其末尾创建的单元。

  

由该线程在STA公寓中创建的对象的所有调用都应由该线程执行。

对于属于STA的对象:是和否。 “否”是因为由于我之前提到的特殊(讨厌的)魔术(代理和存根),您可以在STA#2的另一个线程上获得对属于STA#1的COM对象的引用,从那里打电话。 “是”是因为在后台发生的事情是代理/存根魔术从一个线程向另一个线程发送消息,并且该方法实际上始终在对象所属的线程上执行。因此,您可以从任何线程/启动/跨部门调用...但是方法本身将在对象所属的线程上执行。一个经常出现的问题是,由于某种原因,代理/存根魔术对于给定的COM对象不可用...在这种情况下,您会被卡住;您实际上只能在该对象所在的线程上直接使用该对象。

对于MTA,它稍微宽松一些-特殊的(烦人的)封送处理功能仅在跨越公寓边界而不是线程边界时才起作用。因此,如果您的MTA中有多个线程,则必须谨慎处理自己的同步。