Использование многопоточного компонента WinRT из WinJS
У меня есть приложение WinJS, которое использует компонент WinRT, написанный на C++/CX. Компонент порождает фоновый поток, который инкапсулирует работу с огромной устаревшей небезопасной библиотекой C++, которая требует, чтобы все вызовы выполнялись из одного потока.
Мне нужно реализовать шаблон производителя / потребителя, где фоновый поток в компоненте является производителем, а поток пользовательского интерфейса в приложении JavaScript является потребителем.
Часть вызова проста, так как JavaScript может вызывать методы компонентов (в потоке пользовательского интерфейса), а код C++ помещает задание в очередь для фонового потока.
Вопрос в обратном вызове: мне нужно опубликовать данные, рассчитанные фоновым потоком C++, в поток пользовательского интерфейса. Я, конечно, могу вернуть IAsyncOperation обратно в JavaScript, но я не хочу, чтобы поток пользовательского интерфейса был заблокирован, пока эта операция ожидает событие из фонового потока.
Какие у меня варианты?
2 ответа
Решаемые. Посмотрите на раздел: "Чтобы добавить асинхронный метод, который запускает события..." http://msdn.microsoft.com/en-us/library/windows/apps/hh755833.aspx.
Идея состоит в том, что класс компонента объявляет обработчик события (делегат), который может быть установлен в JavaScript. Фоновый поток C++ может инициировать событие в контексте потока пользовательского интерфейса, поэтому обработчик событий JavaScript называется правильным способом.
Конечно, это может быть легко помещено в WinJS.Promise, поэтому код приложения JavaScript не будет знать о наличии компонентов, событий и т. Д.
Если вы реализуете IAsyncOperation в C++/CX на стороне Javascript, это представит обещание. Для выполнения обещания не блокировать поток пользовательского интерфейса вы можете
- Либо реализуйте вращение работы в асинхронном режиме (например, с использованием потоков) и управляйте обратными вызовами самостоятельно.
- Используйте библиотеку PPL, которая создает простые обертки вокруг лямда-выражений.
В случае использования PPL вы можете использовать concurrency::create_async для преобразования лямбда-выражения в IAsyncOperation, выполняемый в отдельном потоке, например:
#include <thread>
#include <ppltasks.h>
IAsyncOperation<int64>^ Class1::GetAnswer()
{
return create_async([]() -> int64{
std::this_thread::sleep_for(std::chrono::seconds(10));
return 42;
});
}
Со стороны Javascript вы можете использовать эту IAsyncOperation в качестве обещания - без фактической работы, вешающей поток пользовательского интерфейса:
var nativeObject = new CPPComponent.Class1();
nativeObject.getAnswer().then(function(value){
// do something with the result
});