需要有关COM与TPL行为的帮助

时间:2012-07-11 19:43:55

标签: winforms com console task-parallel-library

我需要一些帮助来理解关于winform和控制台应用程序的STA和MTA之间的区别。我使用parallel.invoke使用第三方COM接口并行执行函数。当我在控制台应用程序中执行此操作时,一切正常,代码实际上并行运行。但是当我在Winform中执行相同的操作时,它是顺序的,如果我删除了winform入口点上方的STAtrhread标记,它就会开始并行工作。任何人都可以解释这种行为吗?,任何建议都会很好!

2 个答案:

答案 0 :(得分:1)

COM有一个在.NET中完全缺失的功能。 COM类可以指定它是否是线程安全的。它通过名为ThreadingModel的注册表中的密钥来实现。就像大多数.NET类一样,绝大多数COM类都不是线程安全的,因此它们指定了“Apartment”。这是一个有点模糊的术语,暗示“只从我创建的帖子中打电话给我”。这会自动提供线程安全性。

为了实现这一目标,创建COM对象的线程必须指出它愿意为非线程安全的COM类提供何种类型的支持。 STA线程是一个安全的家。要求是线程泵出消息循环,就像任何UI线程一样。消息循环是COM将来自工作线程的调用封送到创建该对象的线程的机制。加入MTA的线程明确表示它提供支持。

COM必须对MTA线程做一些事情,它们不适合非线程安全的COM对象。它创建了一个 new 线程,一个STA线程,为COM对象提供了一个安全的家。这是非常低效的,每个方法调用都必须被编组。如果它的对象在内部共享状态,那么COM类可能仍然是线程不安全的。

因此,Winforms案例中发生的事情是您在主线程(即STA)上创建了所有对象。并且从并行工作线程调用,这些调用都被编组并序列化回STA线程。不可避免地,它们一个接一个地执行,而你却没有并发。

在您的控制台案例中,您是在MTA线程上创建的。因此,COM被迫为每个对象创建线程。您的工作线程的方法调用仍然被封送,但现在到多个线程。所以现在你获得并发,代价是显着的开销,一堆额外的线程。以及服务器在内部共享状态时发生故障的风险。

通过在工作线程上创建COM对象,使Winforms案例与Console案例相同。做得非常彻底。

答案 1 :(得分:0)

STA和MTA都是COM / ActiveX的“线程模型”,可以追溯到1990年代中期。

这是一个很好的链接:

  
      
  • STA:
  •   
     

进程为每个线程都有一个单线程单元(STA)   叫做CoInitialize。反过来,这些公寓中的每一个都可能为零   或更多与之关联的COM对象。顾名思义,   但是,只有一个特定的线程(创建该线程的线程)   公寓通过调用CoInitialize)可以直接访问对象   在公寓内

     
      
  • MTA:
  •   
     虽然多线程公寓,有时也称为自由线程   公寓,是一个更简单的模型,他们更难   开发因为开发人员必须实现该线程   对象的同步,这是一项非常重要的任务。在   积极的一面,删除STA的同步机制给出了   开发人员更精细地控制线程同步的使用。   他们可以在实际需要的地方使用它而不是服用它   非常保守的STA方法,它同步访问   整个公寓。

一个问题是为您的组件选择最佳线程模型(默认为STA,IIRC)。另一个问题是,如果需要在组件和使用不同线程模型的组件之间编组数据,运行时将执行的操作。上面的链接讨论了两者。