Can the .NET 4 Task Parallel Library use COM objects?

This is an "is this possible, and if so can you give me a quick example because I can't find one online?" kind of question.

I have a number of completely separate (ie "embarrassingly parallel") processes that I want to run in parallel using the Task Parallel library in .NET Framework 4 using C#. Some of these processes require the use of software that can be accessed via COM/OLE automation.

Specifically, there is a Parallel.Foreach() loop that divides up the tasks from a list of items, basically calling a different function inside the Parallel.Foreach to handle the processing (so some of these functions employ COM libraries to work).

Is this possible? Thanks.


It's 100% possible to use COM objects with the TPL. While it's true that, by default, the TPL will use the standard .NET ThreadPool, the TPL has an extension point via the TaskScheduler class which enables you to provide your own scheduler which can dispatch work to threads which you've created.

In the case of of using COM objects you first need to know if the COM class requires STA threading or MTA threading. If MTA threading, then there's nothing special that needs to be done because the COM class can already be used from any random thread. Unfortunately most classic COM objects tend to rely on STA threading and that's when you'd need to employ a custom TaskScheduler so that whatever .NET thread you're using them from has been initialized as an STA compatible thread.

While TaskSchedulers are not exactly trivial to write, they're not really that hard to write either if you've got a basic understanding of threading. Luckily the ParallelExtensions Extras library already provides an StaTaskScheduler class so you don't even need to write anything yourself. There's a great blog post here by the PFX team that discusses the implementation of and some use cases for the the StaTaskScheduler class.

Basically though, you'll want to initialize a new StaTaskScheduler as a static somewhere on one of your classes and then just start your Tasks specifying that they are scheduled by that instance. That would look something like this:

// 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);

It's potentially possible, but it may also not work.

Many COM objects require a specific apartment threading. When you use Parallel.For/ForEach, you're running on the .NET ThreadPool, which doesn't have the apartment threading setup. This may work, and can for some COM objects, but can also cause crashes and strange COM exceptions that are difficult to track down.


Some additional information that I am yet to verify, but that may be helpful. The default task scheduler will use the current thread to do some of the work then add additional threads from the thread pool as necessary.

This could cause problems if you are sharing a COM object when doing Parallel.ForEach. For example, let's say your main thread is STA. You instantiate the COM object on that and use Parallel.ForEach to do some work where each thread tries to access the previously instantiated COM object. I suspect that it will break, and initial testing seems to back this up. In this scenario I see at least a couple of options:

  • Assuming the COM object supports MTA, have the calling thread use MTA. However this may not be an option for other reasons. For example, if the application is a Windows Forms application I believe Main() is required to have the STAThread attribute.
  • Use an alternative task scheduler such as the StaTaskScheduler mentioned by Drew. You could either have all STA threads or use a scheduler that does not use the calling thread and run all MTA threads.
  • 链接地址: http://www.djcxy.com/p/50152.html

    上一篇: C#平行foreach同样完成任务

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