.NET 4任务并行库可以使用COM对象吗?

时间:2011-02-10 21:47:33

标签: c# com .net-4.0 ole task-parallel-library

这是“这是可能的,如果是这样,你能给我一个简单的例子,因为我找不到一个在线的吗?”有点问题。

我有许多完全独立的(即“令人尴尬的并行”)进程,我想使用C#在.NET Framework 4中使用任务并行库并行运行。其中一些过程需要使用可通过COM / OLE自动化访问的软件。

具体来说,有一个Parallel.Foreach()循环将任务从项列表中分开,基本上调用Parallel.Foreach中的不同函数来处理处理(所以这些函数中的一些使用COM库来工作)。

这可能吗?感谢。

3 个答案:

答案 0 :(得分:18)

将100%的COM对象与TPL一起使用是可能的。虽然默认情况下TPL将使用标准的.NET ThreadPool,但TPL有一个扩展点the TaskScheduler class,这使您可以提供自己的调度程序,可以将工作分派给您创建的线程。

在使用COM对象的情况下,首先需要知道COM类是否需要STA线程或MTA线程。如果是MTA线程,则没有什么特别需要完成的,因为COM类已经可以在任何随机线程中使用。不幸的是,大多数经典的COM对象往往依赖于STA线程,当你需要使用自定义TaskScheduler时,无论你使用它们的.NET线程是initialized as an STA compatible thread还是{/ 3}。

虽然TaskSchedulers写起来并不是一件容易的事,但如果您对线程有基本的了解,那么它们写起来并不是那么难。幸运的是the ParallelExtensions Extras library已经提供了StaTaskScheduler课程,所以你甚至不需要自己写任何东西。 PFX团队有a great blog post here讨论了StaTaskScheduler类的实现和一些用例。

但基本上,您需要在其中一个类的某处将新StaTaskScheduler初始化为静态,然后启动Tasks,指定它们是由该实例调度的。这看起来像这样:

// Create a static instance of the scheduler specifying some max number of threads
private static readonly StaTaskScheduler MyStaTaskScheduler = new StaTaskScheduler(4);

....

// Then specify the scheduler when starting tasks that need STA threading
Task.TaskFactory.StartNew(
() =>
{
    MyComObject myComObject = new MyComObject();

    myComObject.DoSomething();

    // ... etc ...
},
CancellationToken.None,
TaskCreationOptions.None,
MyStaTaskScheduler);

答案 1 :(得分:2)

这可能是有可能的,但也可能不起作用。

许多COM对象需要特定的apartment threading。当您使用Parallel.For / ForEach时,您正在.NET ThreadPool上运行,它没有公寓线程设置。这可能有用,可以用于某些COM对象,但也可能导致崩溃和难以追踪的奇怪COM异常。

答案 2 :(得分:0)

我还要验证一些其他信息,但这可能会有所帮助。默认任务调度程序将使用当前线程执行某些工作,然后根据需要从线程池中添加其他线程。

如果在执行Parallel.ForEach时共享COM对象,则可能会出现问题。例如,假设您的主线程是STA。您在其上实例化COM对象并使用Parallel.ForEach做一些工作,其中每个线程尝试访问以前实例化的COM对象。我怀疑它会破裂,初步测试似乎支持这一点。在这种情况下,我至少看到了几个选项:

  • 假设COM对象支持MTA,请让调用线程使用MTA。然而,由于其他原因,这可能不是一种选择。例如,如果应用程序是Windows窗体应用程序,我认为Main()需要具有STAThread属性。
  • 使用替代任务计划程序,例如Drew提到的StaTaskScheduler。您可以拥有所有STA线程,也可以使用不使用调用线程的调度程序并运行所有MTA线程。