Практическое руководство. Завершение асинхронных операций с использованием WRL
Это руководство показывает, как использовать Библиотека шаблонов C++ среды выполнения Windows (WRL) для запуска асинхронных операций и выполнить работу после начала операции.
В следующем примере показан документ 2.Первый пример запускает асинхронный таймер и ожидает таймер, чтобы срок действия.В этом примере указывается асинхронного действия при создании объекта таймера.Во втором примере выполняется фоновый рабочего потока.В этом примере показано, как работать с методом Среда выполнения Windows, который возвращает интерфейс IAsyncInfo.Функция Обратный вызов является важной частью обоих примеров, так как они позволяют определить процесс обработчика событий результаты асинхронных операций.
Для более базового примера, который создает экземпляр этого компонента и получает значение свойства см. в разделе Практическое руководство. Активация и использование компонента среды выполнения Windows с помощью WRL.
![]() |
---|
В этих примерах лямбда-выражения для определения обратные вызовы.Можно также использовать объекты функций (functors), вызов функции или объекты std::function.Дополнительные сведения о лямбда-выражениях C, C-++, см. в разделе Lambda expressions in C++. |
Пример: Работа с таймером
Следующие шаги асинхронного начала и таймер ожидания таймера, чтобы срок действия.Полный пример кода выглядит следующим образом.
![]() |
---|
Хотя обычно используется WRL в приложении Магазина Windows, в этом образце используется приложение консоли для иллюстрации.Функции, такие как wprintf_s, не доступны из приложения Магазина Windows.Дополнительные сведения о типах и функциях, которые можно использовать в приложении Магазина Windows см. в разделе Функции CRT не поддерживаются при /ZW и Win32 и модели COM для приложений Windows Магазина. |
Включите (#include) все необходимое Среда выполнения Windows, WRL или стандартные заголовки библиотеки времени выполнения C и C-++.
#include <Windows.Foundation.h> #include <Windows.System.Threading.h> #include <wrl/event.h> #include <stdio.h> #include <Objbase.h> using namespace ABI::Windows::Foundation; using namespace ABI::Windows::System::Threading; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers;
Windows.System.Threading.h объявляет типы, необходимые для использования асинхронного таймер.
Рекомендуется использовать директиву using namespace в cpp-файле, чтобы сделать код более удобочитаемым.
Инициализация Среда выполнения Windows.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Создание фабрики активации для интерфейса ABI::Windows::System::Threading::IThreadPoolTimer.
// Get the activation factory for the IThreadPoolTimer interface. ComPtr<IThreadPoolTimerStatics> timerFactory; HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
В Среда выполнения Windows используются полные имена для определения типов.Параметр RuntimeClass_Windows_System_Threading_ThreadPoolTimer является строкой, предоставляемой Среда выполнения Windows и содержит требуемое имя класса среды выполнения.
Создайте объект События, который синхронизирует обратный вызов таймера к основному приложению.
// Create an event that is set after the timer callback completes. We later use this event to wait for the timer to complete. // This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete. Event timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS)); hr = timerCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError()); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Примечание
Это событие для демонстрации только в составе приложения консоли.В этом примере используется событие, чтобы гарантировать, что операция токена, прежде чем приложение не влияет.В большинстве приложений, обычно не ожидает операции токена для выполнения.
Создайте объект IThreadPoolTimer, истекает через 2 секунд.Используйте функцию Callback, чтобы создать обработчик событий (объект ABI::Windows::System::Threading::ITimerElapsedHandler ).
// Create a timer that prints a message after 2 seconds. TimeSpan delay; delay.Duration = 20000000; // 2 seconds. auto callback = Callback<ITimerElapsedHandler>([&timerCompleted](IThreadPoolTimer* timer) -> HRESULT { wprintf_s(L"Timer fired.\n"); TimeSpan delay; HRESULT hr = timer->get_Delay(&delay); if (SUCCEEDED(hr)) { wprintf_s(L"Timer duration: %2.2f seconds.\n", delay.Duration / 10000000.0); } // Set the completion event and return. SetEvent(timerCompleted.Get()); return hr; }); hr = callback ? S_OK : E_OUTOFMEMORY; if (FAILED(hr)) { return PrintError(__LINE__, hr); } ComPtr<IThreadPoolTimer> timer; hr = timerFactory->CreateTimer(callback.Get(), delay, &timer); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Выведите сообщение на консоль и дождитесь обратный вызов таймера для выполнения.Все объекты ComPtr и RAII покидает область и освобождаются автоматически.
// Print a message and wait for the timer callback to complete. wprintf_s(L"Timer started.\nWaiting for timer...\n"); // Wait for the timer to complete. WaitForSingleObjectEx(timerCompleted.Get(), INFINITE, FALSE); // All smart pointers and RAII objects go out of scope here.
Ниже приведен полный пример.
// wrl-consume-async.cpp
// compile with: runtimeobject.lib
#include <Windows.Foundation.h>
#include <Windows.System.Threading.h>
#include <wrl/event.h>
#include <stdio.h>
#include <Objbase.h>
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
// Prints an error string for the provided source code line and HRESULT
// value and returns the HRESULT value as an int.
int PrintError(unsigned int line, HRESULT hr)
{
wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
return hr;
}
int wmain()
{
// Initialize the Windows Runtime.
RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize))
{
return PrintError(__LINE__, initialize);
}
// Get the activation factory for the IThreadPoolTimer interface.
ComPtr<IThreadPoolTimerStatics> timerFactory;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Create an event that is set after the timer callback completes. We later use this event to wait for the timer to complete.
// This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete.
Event timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
hr = timerCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Create a timer that prints a message after 2 seconds.
TimeSpan delay;
delay.Duration = 20000000; // 2 seconds.
auto callback = Callback<ITimerElapsedHandler>([&timerCompleted](IThreadPoolTimer* timer) -> HRESULT
{
wprintf_s(L"Timer fired.\n");
TimeSpan delay;
HRESULT hr = timer->get_Delay(&delay);
if (SUCCEEDED(hr))
{
wprintf_s(L"Timer duration: %2.2f seconds.\n", delay.Duration / 10000000.0);
}
// Set the completion event and return.
SetEvent(timerCompleted.Get());
return hr;
});
hr = callback ? S_OK : E_OUTOFMEMORY;
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
ComPtr<IThreadPoolTimer> timer;
hr = timerFactory->CreateTimer(callback.Get(), delay, &timer);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Print a message and wait for the timer callback to complete.
wprintf_s(L"Timer started.\nWaiting for timer...\n");
// Wait for the timer to complete.
WaitForSingleObjectEx(timerCompleted.Get(), INFINITE, FALSE);
// All smart pointers and RAII objects go out of scope here.
}
/*
Output:
Timer started.
Waiting for timer...
Timer fired.
Timer duration: 2.00 seconds.
*/
Компиляция кода
Чтобы компилировать код, он скопируйте и вставьте его в проект Visual Studio, или в файл с именем wrl-consume-async.cpp, затем выполните следующую команду в окне командной строки Visual Studio.
cl.exe wrl-consume-async.cpp runtimeobject.lib
Пример: Работа с фоновым потоком
Следующие действия запускают рабочий поток и указать действие, которое выполняется этим потоком.Полный пример кода выглядит следующим образом.
![]() |
---|
В этом примере показано, как работать с использованием интерфейса ABI::Windows::Foundation::IAsyncAction.Можно применить к любому этот шаблон, который реализует интерфейс IAsyncInfo. IAsyncAction, IAsyncActionWithProgress, IAsyncOperation и IAsyncOperationWithProgress. |
Включите (#include) все необходимое Среда выполнения Windows, WRL или стандартные заголовки библиотеки времени выполнения C и C-++.
#include <Windows.Foundation.h> #include <Windows.System.Threading.h> #include <wrl/event.h> #include <stdio.h> #include <Objbase.h> using namespace ABI::Windows::Foundation; using namespace ABI::Windows::System::Threading; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers;
Windows.System.Threading.h объявляет типы, необходимые для используют рабочего потока.
Рекомендуется использовать директиву using namespace в cpp-файле, чтобы сделать код более удобочитаемым.
Инициализация Среда выполнения Windows.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Создание фабрики активации для интерфейса ABI::Windows::System::Threading::IThreadPoolStatics.
// Get the activation factory for the IThreadPoolStatics interface. ComPtr<IThreadPoolStatics> threadPool; HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &threadPool); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Создайте объект События, который синхронизирует завершение рабочего потока к основному приложению.
// Create an event that is set after the timer callback completes. We later use this event to wait for the timer to complete. // This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete. Event threadCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS)); hr = threadCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError()); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Примечание
Это событие для демонстрации только в составе приложения консоли.В этом примере используется событие, чтобы гарантировать, что операция токена, прежде чем приложение не влияет.В большинстве приложений, обычно не ожидает операции токена для выполнения.
Вызовите метод IThreadPoolStatics::RunAsync для создания рабочего потока.Используйте функцию Callback для задания действия.
wprintf_s(L"Starting thread...\n"); // Create a thread that computes prime numbers. ComPtr<IAsyncAction> asyncAction; hr = threadPool->RunAsync(Callback<IWorkItemHandler>([&threadCompleted](IAsyncAction* asyncAction) -> HRESULT { // Print a message. const unsigned int start = 0; const unsigned int end = 100000; unsigned int primeCount = 0; for (int n = start; n < end; n++) { if (IsPrime(n)) { primeCount++; } } wprintf_s(L"There are %u prime numbers from %u to %u.\n", primeCount, start, end); // Set the completion event and return. SetEvent(threadCompleted.Get()); return S_OK; }).Get(), &asyncAction); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Функция IsPrime задается в полном примере следующего.
Выведите сообщение на консоль и дождитесь поток для выполнения.Все объекты ComPtr и RAII покидает область и освобождаются автоматически.
// Print a message and wait for the thread to complete. wprintf_s(L"Waiting for thread...\n"); // Wait for the thread to complete. WaitForSingleObjectEx(threadCompleted.Get(), INFINITE, FALSE); wprintf_s(L"Finished.\n"); // All smart pointers and RAII objects go out of scope here.
Ниже приведен полный пример.
// wrl-consume-asyncOp.cpp
// compile with: runtimeobject.lib
#include <Windows.Foundation.h>
#include <Windows.System.Threading.h>
#include <wrl/event.h>
#include <stdio.h>
#include <Objbase.h>
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
// Prints an error string for the provided source code line and HRESULT
// value and returns the HRESULT value as an int.
int PrintError(unsigned int line, HRESULT hr)
{
wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
return hr;
}
// Determines whether the input value is prime.
bool IsPrime(int n)
{
if (n < 2)
{
return false;
}
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
{
return false;
}
}
return true;
}
int wmain()
{
// Initialize the Windows Runtime.
RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize))
{
return PrintError(__LINE__, initialize);
}
// Get the activation factory for the IThreadPoolStatics interface.
ComPtr<IThreadPoolStatics> threadPool;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &threadPool);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Create an event that is set after the timer callback completes. We later use this event to wait for the timer to complete.
// This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete.
Event threadCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
hr = threadCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
wprintf_s(L"Starting thread...\n");
// Create a thread that computes prime numbers.
ComPtr<IAsyncAction> asyncAction;
hr = threadPool->RunAsync(Callback<IWorkItemHandler>([&threadCompleted](IAsyncAction* asyncAction) -> HRESULT
{
// Print a message.
const unsigned int start = 0;
const unsigned int end = 100000;
unsigned int primeCount = 0;
for (int n = start; n < end; n++)
{
if (IsPrime(n))
{
primeCount++;
}
}
wprintf_s(L"There are %u prime numbers from %u to %u.\n", primeCount, start, end);
// Set the completion event and return.
SetEvent(threadCompleted.Get());
return S_OK;
}).Get(), &asyncAction);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Print a message and wait for the thread to complete.
wprintf_s(L"Waiting for thread...\n");
// Wait for the thread to complete.
WaitForSingleObjectEx(threadCompleted.Get(), INFINITE, FALSE);
wprintf_s(L"Finished.\n");
// All smart pointers and RAII objects go out of scope here.
}
/*
Output:
Starting thread...
Waiting for thread...
There are 9592 prime numbers from 0 to 100000.
Finished.
*/
Компиляция кода
Чтобы компилировать код, он скопируйте и вставьте его в проект Visual Studio, или в файл с именем wrl-consume-asyncOp.cpp, затем выполните следующую команду в окне командной строки Visual Studio.
cl.exe wrl-consume-asyncOp.cpp runtimeobject.lib