Comment : terminer une opération asynchrone à l'aide de WRL
Ce document montre comment utiliser Bibliothèque de modèles Windows Runtime C++ (WRL) pour démarrer les opérations asynchrones et pour effectuer le travail lorsque les opérations se terminent.
Ce document montre deux exemples.Le premier exemple démarre une minuterie asynchrone et attend le délai d'attente expire.Dans cet exemple, vous spécifiez l'action asynchrone lorsque vous créez l'objet de minuterie.Le deuxième exemple exécute un thread de travail d'arrière-plan.Cet exemple montre comment utiliser une méthode d' Windows Runtime qui retourne une interface d' IAsyncInfo .La fonction d' Rappel est une proportion significative des deux exemples car elle leur permet de spécifier un gestionnaire d'événements pour traiter les résultats des opérations asynchrones.
Pour un exemple plus fondamental qui crée une instance de ce composant et récupère une valeur de propriété, consultez Comment : activer et utiliser un composant Windows Runtime Component à l'aide de WRL.
Conseil |
---|
Ces exemples utilisent des expressions lambda pour définir les rappels.Vous pouvez également utiliser des objets de fonction (functors), les pointeurs fonction, les objets ou d' std::function .Pour plus d'informations sur les expressions lambda C++, consultez Expressions lambda en C++. |
Exemple : Utiliser une minuterie
Les étapes suivantes mettent en démarre une minuterie asynchrone et attendent le délai d'attente expire.Voici un exemple de code complet :
Attention |
---|
Bien que vous utilisez en général WRL dans une application d' Windows Store, cet exemple utilise une application console pour l'illustration.Les fonctions telles qu' wprintf_s sont pas disponibles d'une application d' Windows Store .Pour plus d'informations sur les types et les fonctions que vous pouvez utiliser dans une application d' Windows Store, consultez Fonctions CRT non prises en charge avec /ZW et Win32 et COM pour les applications de mémoire windows. |
Incluez (#include) tous les Windows Runtimerequis, WRL, ou en-tête standard de bibliothèque 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 déclare les types requis pour utiliser une minuterie asynchrone.
Nous vous recommandons d'utiliser la directive d' using namespace dans votre fichier .cpp pour rendre le code plus lisible.
Initialisez Windows Runtime.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Créez une fabrique de lancement pour l'interface d' 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); }
Les noms complets des utilisations d' Windows Runtime pour identifier des types.Le paramètre d' RuntimeClass_Windows_System_Threading_ThreadPoolTimer est une chaîne fournie par Windows Runtime et contient le nom de classe d'exécution obligatoire.
Créez un objet d' Événement qui synchronise le rappel de minuterie à l'application principale.
// 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); }
[!REMARQUE]
Cet événement est pour une démonstration uniquement dans le cadre d'une application de console.Cet exemple utilise l'événement pour vérifier qu'une opération async se termine avant les sorties d'application.Dans la plupart des applications, vous devez généralement n'attendez pas d'opérations async se termine.
Créez un objet d' IThreadPoolTimer qui expire après deux secondes.Utilisez la fonction d' Callback pour créer le gestionnaire d'événements (un objet d' 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); }
Imprimez un message dans la console et que le rappel de minuterie se termine.Tous les ComPtr et les objets RAII de la portée et est libéré automatiquement.
// 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.
Voici l'exemple complet :
// 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.
*/
Compilation du code
Pour compiler le code, copiez-le puis collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé wrl-consume-async.cpp puis exécutez la commande suivante dans une fenêtre d'invite de commandes de Visual Studio.
cl.exe wrl-consume-async.cpp runtimeobject.lib
Exemple : Utiliser un thread d'arrière-plan
Les étapes suivantes démarrent un thread de travail et définissent l'action qui est exécutée par ce thread.Voici un exemple de code complet :
Conseil |
---|
Cet exemple montre comment utiliser l'interface d' ABI::Windows::Foundation::IAsyncAction .Vous pouvez implémenter ce modèle à une interface qui implémente IAsyncInfo: IAsyncAction, IAsyncActionWithProgress, IAsyncOperation, et IAsyncOperationWithProgress. |
Incluez (#include) tous les Windows Runtimerequis, WRL, ou en-tête standard de bibliothèque 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 déclare les types requis pour utiliser un thread de travail.
Nous vous recommandons d'utiliser la directive d' using namespace dans votre fichier .cpp pour rendre le code plus lisible.
Initialisez Windows Runtime.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Créez une fabrique de lancement pour l'interface d' 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); }
Créez un objet d' Événement qui synchronise l'achèvement du thread de travail à l'application principale.
// 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); }
[!REMARQUE]
Cet événement est pour une démonstration uniquement dans le cadre d'une application de console.Cet exemple utilise l'événement pour vérifier qu'une opération async se termine avant les sorties d'application.Dans la plupart des applications, vous devez généralement n'attendez pas d'opérations async se termine.
Appelez la méthode d' IThreadPoolStatics::RunAsync pour créer un thread de travail.Utilisez la fonction d' Callback pour définir l'action.
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); }
La fonction d' IsPrime est définie dans l'exemple complet qui suit.
Imprimez un message dans la console et que le thread se termine.Tous les ComPtr et les objets RAII de la portée et est libéré automatiquement.
// 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.
Voici l'exemple complet :
// 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.
*/
Compilation du code
Pour compiler le code, copiez-le puis collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé wrl-consume-asyncOp.cpp puis exécutez la commande suivante dans une fenêtre d'invite de commandes de Visual Studio.
cl.exe wrl-consume-asyncOp.cpp runtimeobject.lib