Using multithreaded WinRT component from WinJS

1.3k Views Asked by At

I have a WinJS app that uses WinRT component written in C++/CX. Component spawns a background thread that encapsulates work with a huge legacy thread-unsafe C++ library, which requires all calls to be made from the same thread.

I need to implement a producer/consumer pattern, where the background thread in the component is a producer, and UI thread in JavaScript app is a consumer.

The call part is easy, as JavaScript can call component methods (in UI thread), and C++ code will post a job into a queue for background thread.

The question is the callback: I need to post the data calculated by the C++ background thread into UI thread. I certainly can return an IAsyncOperation back to JavaScript, but I don't want UI thread to be blocked while this operation is waiting for an event from a background thread.

What are my options?

2

There are 2 best solutions below

0
On BEST ANSWER

Solved. Look at the section: "To add an asynchronous method that fires events..." of https://learn.microsoft.com/en-us/windows/uwp/winrt-components/walkthrough-creating-a-basic-windows-runtime-component-in-cpp-and-calling-it-from-javascript-or-csharp.

The idea is that component class declares an event handler (delegate), which can be set in JavaScript. C++ background thread can fire an event in the context of UI thread, so JavaScript event handler is called right way.

Of course, this can easily be wrapped into WinJS.Promise, so JavaScript application code won't know that there are components, events etc.

1
On

If you implement IAsyncOperation in C++/CX on the Javascript side this will expose a promise. In order for the execution of the promise not to block the UI thread you can

  • Either implement spinning of work in asynchronously (e.g. using threawds) and managing callbacks yourself
  • Use the PPL library that creates simple wrappers around lamda expressions.

In the case of using PPL you can use concurrency::create_async to convert a lambda into an IAsyncOperation executing on a separate thread, e.g.:

#include <thread>
#include <ppltasks.h>
IAsyncOperation<int64>^ Class1::GetAnswer()
{ 
    return create_async([]() -> int64{
        std::this_thread::sleep_for(std::chrono::seconds(10));
        return 42;
    });
}

On the Javascript side you can consume this IAsyncOperation as a promise - without the actual work hanging the UI thread:

var nativeObject = new CPPComponent.Class1();
  nativeObject.getAnswer().then(function(value){
    // do something with the result
  });