0

I start a Task from the main (GUI) thread, and await for it.
It runs long time, but does not block the GUI. Nice.
However, if I call a COM function in it, it blocks the main thread.
Code:

class TaskCreater
{
    internal System.Threading.Tasks.Task Run()
    {
        return System.Threading.Tasks.Task.Run(() =>
        {
            System.Threading.Thread.Sleep(10000); // --> nice, no blocking GUI for 10 sec

            COMClass.LongFunction(); // -> not nice, blocks to GUI
        });
    }
}

Caller GUI thread:

  await _taskCreator.Run();

MSDN: Task.Run Method: Queues the specified work to run on the ThreadPool and returns a task or Task handle for that work.

So why is then that COM call blocks the caller thread?
And why Sleep() does not then?
I expect both to run in a background thread.

Zoli
  • 841
  • 8
  • 31
  • Which COM functions have you tried? – Gabriel Luci Oct 31 '19 at 12:28
  • @GabrielLuci: it's our own. Made in VC++ – Zoli Oct 31 '19 at 12:31
  • 1
    What is the thread model of your COM object - STA, MTA? – Nick Oct 31 '19 at 12:36
  • The main App (exe) is a .NET Forms, and STA: `[STAThread] static void Main(string[] args)` – Zoli Oct 31 '19 at 12:42
  • Nick was asking about COM object not C# project .... the problem is inside COM implementation .... please provide minimal COM implementation which blocks ... – Selvin Oct 31 '19 at 12:43
  • 1
    That's pretty normal for COM libraries, the runtime ensures that they are used in a thread-safe way. Which often means that any method calls execute on the same thread on which the object was created because the vast majority of those libraries tell the OS that they are not thread-safe. Same mechanism as Invoke() in .NET, but completely automagic. So you must create the object on the same thread *and* give the object a home that it is happy with so it doesn't try to find one by itself. Sample code [is here](https://stackoverflow.com/a/21684059/17034). – Hans Passant Oct 31 '19 at 12:52
  • @Selvin: _ATL_APARTMENT_THREADED – Zoli Oct 31 '19 at 13:01
  • @HansPassant: so, if I create the COM object inside the Task body, it would run on that thread instead of the GUI? – Zoli Oct 31 '19 at 13:04
  • 1
    No, the COM infrastructure is forced to create the "happy home", an STA thread. Adds lots of overhead to the function calls, Invoke() is slow. You get ahead of it by creating your own STA thread, as shown in the sample code. – Hans Passant Oct 31 '19 at 13:21
  • Sounds pretty ugly. The reason I need to use COM is that some libs are in native C++, so that's a simple bridge between .net and native. But seeing this, I will probably just create a managed C++ wrapper around the native lib function. – Zoli Oct 31 '19 at 13:25
  • @HansPassant: I **think** your hint could be the solution, so if you write it out as an answer, I can accept. – Zoli Oct 31 '19 at 13:32
  • Just publish your COM coclass correctly. If it is *actually* thread-safe then set the ThreadingModel registry key accordingly, use "Free". Such a strong guarantee needs to be tested of course, no different from what you have to do if you create a C++/CLI wrapper. – Hans Passant Oct 31 '19 at 13:35
  • No, not thread safe, except some functions... – Zoli Oct 31 '19 at 13:39
  • One more interesting thing: from other thread, even casting to COM interface also fails! So `obj as ICOMInterface1` will result in null from the worker thread (when obj is implementing ICOMInterface1) while it will be a valid ICOMInterface1 in the main thread. Stole 3 hours from my life... – Zoli Nov 01 '19 at 12:37
  • You need a concept of workers, this will be transient and then a caller engine that is a singleton gets a new instance of that worker and gives the order to start, this way the worker will not interfere with the caller engine. – Pedro Brito Nov 19 '19 at 17:18

0 Answers0