none
how to combine COM and OpenMP RRS feed

  • Question

  • hi, gurus

    I'm trying to use OpenMP to speed up one of my existing big Applications. The Application is developed under Microsoft COM environment. I've two questions:

    1) how to create COM context for OpenMP threads. E.g. I've a code like this:

    ...
    CoInitializeEx(NULL,MTA);
    for()
    {
    ...
    }

    Now if I want to paralyze the for loop, what I would deal with the CoInitializeEx? I tried the following way. Basically, it can work. But I don't know whether there're some potential issues:

    ...
    CoInitializeEx(NULL,MTA);
    #pragma omp parallel for
    for()
    {
    CoInitializeEx(NULL,MTA);
    ...
    }

    2. We've many COM Interface pointers, which have been created before my paralleled part. How can I share these pointers between all the threads created by OpenMP. I suppose I can use some Marshal or GIT technology to transmit the pointer accross threads. However, the number of them is very big, so is there any easier way for me?

    Thanks!

    John
    Tuesday, April 14, 2009 1:19 AM

Answers

All replies

  • There are lots of problems with using COM in an OpenMP parallel region.  The biggest one with

    ...
    CoInitializeEx(NULL,MTA);
    #pragma omp parallel for
    for()
    {
    CoInitializeEx(NULL,MTA);
    ...
    }

    is that the CoInitEx inside the for-loop may execute many times on the same thread, and you really can't know in advance how many times extra on each thread (it may very from machine to machine).  Normally this is not fatal (it simply returns S_FALSE), but if you want to properly uninitialize COM you have to call CoUninitialize a balancing number of times on each thread.  (You may leak objects if the apartments aren't properly uninitialized.)  I think there's also an issue that one of the threads in the parallel region is the same thread that called CoInit prior to entering the parallel region... thus another double CoInit.

    The simple workaround for this is to simply call CoInitializeEx(NULL, MTA) prior to the parallel region.  That essentially says that all threads in the process that aren't STA's are MTA's (including OpenMP's threads).  The COM guys might shoot me for saying so, but a lot of apps depend on this behaviour.

    As for sharing interface pointers, I assume these are (potentially) STA objects.  If so, isn't the best way simply to QueryInterface the class instance inside the for-body?  That will ensure the correct proxy gets marshaled to the calling thread.  However, if you're doing this kind of thing in an OpenMP region, I have to ask what kind of perf speed-up you expect?  I would expect very little scalability if you're doing a lot of synchronizing (via STA or self-synchronizing  MTA objects).

    You might get more effective use of OpenMP if you did all your COM work ouside of OpenMP threads, grabbed all the data you needed from them and stored them locally, and then fanned off an OpenMP computation on that data.

    Hope that was helpful.






    ++don;
    Tuesday, April 14, 2009 7:47 PM
  • Don, thanks for your quick answer first.

    For the 1st question, you said "The simple workaround for this is to simply call CoInitializeEx(NULL, MTA) prior to the parallel region.  That essentially says that all threads in the process that aren't STA's are MTA's (including OpenMP's threads)." Do you mean I need to call CoInitializeEx(NULL, MTA) immediately before the parallel region? I mean if my code is like the following, does it have the same effect as you said:

    CoInitializeEx(NULL,MTA);

    // many works are inserted herein.
    ...
    #pragma omp parallel for
    for()
    {

    ...
    }

    For the second question, I encountered a very weird problem. When I share a COM interface between the OpenMP threads (they've been initialized as MTA in the above way), in one of my OpenMP thread, if I call the COM interface, the following error happened:

    "The application called an interface that was marshalled for a different thread."

    But all of my threads are in MTA, and I've checked the callee object's thread model is Free. So, why this happened? One thing is that my application used COM+, is this caused more or less by this?
    Wednesday, April 15, 2009 5:08 AM
  • For the 1st question, yes.  CoInit(MTA) before the parallel region will make all current and future non-STA's into MTA's.

    I can't explain your second problem.  It's possible that COM+ could have something to do with it, but I doubt it.  Marshaling behaviour should be the same for COM and COM+ objects.

    ++don;
    Wednesday, April 15, 2009 8:04 PM
  • Hi, I am currently looking at implementing an OpenMP parallel for loop on a loop that makes calls to COM objects. However, I am finding that performance is much worse in the parallel version of the code versus the serial code. I have been looking at variables that are shared between iterations of the loop, but would also like to learn more about problems in using COM in an OpenMP parallel region.

    To date, I have not found any documentation regarding problems in using COM in an OpenMP parallel region. Don, can you point me in the right direction to find this information? Or can you list some of the problems you are aware of?

    Kind Regards,
    Albert
    Wednesday, April 22, 2009 7:50 PM