Porady: wykonywanie operacji asynchronicznych z użyciem biblioteki WRL

Dokument ten pokazuje sposób używania Biblioteka szablonów C++ środowiska wykonawczego systemu Windows (WRL) do uruchamiania operacji asynchronicznych i wykonywania pracy po ukończeniu operacji.

Ten dokument zawiera dwa przykłady.W pierwszym przykładzie uruchamia Asynchroniczny czasomierz i czeka na czasomierzu.W tym przykładzie zostanie akcja asynchroniczna podczas tworzenia obiektu timer.Drugi przykład działa tła wątku roboczego.Ten przykład pokazuje, jak pracować z Środowisko wykonawcze systemu Windows metoda, która zwraca IAsyncInfo interfejsu.Wywołania zwrotnego funkcja jest ważną częścią obu przykładach, ponieważ umożliwia im określić program obsługi zdarzeń do przetworzenia wyników operacji asynchronicznych.

Na przykład bardziej podstawową, która tworzy wystąpienie składnika i pobiera wartość właściwości, zobacz Porady: uaktywnianie składnika środowiska wykonawczego systemu Windows za pomocą biblioteki WRL i korzystanie z niego.

PoradaPorada

Te przykłady wyrażenia lambda są używane do definiowania wywołania zwrotne.Można również użyć funkcji obiektów (funktory), wskaźników funkcji lub std::function obiektów.Aby uzyskać więcej informacji na temat wyrażeń lambda C++, zobacz Wyrażenia lambda w języku C++.

Przykład: Praca z czasomierzem

Następujące czynności uruchom Asynchroniczny czasomierz i czekać na czasomierzu.Pełny przykład poniżej.

Informacje dotyczące przestrogiPrzestroga

Chociaż zazwyczaj używają WRL w Windows Store aplikacji, w tym przykładzie używa aplikacja konsoli dla celów ilustracyjnych.Funkcji, takich jak wprintf_s nie są dostępne z Windows Store aplikacji.Aby uzyskać więcej informacji na temat typów i funkcji, których można używać w Windows Store aplikacji, zobacz CRT funkcje nie obsługiwane przez /ZW i aplikacje Win32 i COM dla Sklepu Windows.

  1. Obejmują (#include) wszystkie wymagane Środowisko wykonawcze systemu Windows, WRL, lub standard C++ library nagłówków.

    #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 oświadcza, typy, które są zobowiązane do stosowania Asynchroniczny czasomierz.

    Firma Microsoft zaleca, aby wykorzystać using namespace w pliku cpp, aby zwiększyć czytelność kodu w dyrektywie.

  2. Inicjowanie Środowisko wykonawcze systemu Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Utworzyć fabryki aktywacji dla ABI::Windows::System::Threading::IThreadPoolTimer interfejsu.

    // 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);
    }
    

    Środowisko wykonawcze systemu Windows Używa nazwy w pełni kwalifikowane do identyfikacji typów.RuntimeClass_Windows_System_Threading_ThreadPoolTimer Parametr jest ciągiem, który jest udostępniany przez Środowisko wykonawcze systemu Windows i zawiera nazwę klasy wymagane w czasie wykonywania.

  4. Tworzenie zdarzenia obiektu, która synchronizuje czasomierza wywołaniem zwrotnym do głównej aplikacji.

    // 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);
    }
    

    [!UWAGA]

    To zdarzenie jest wykazanie tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenia do zapewnienia, że operacji asynchronicznej zostanie zakończony przed zamyka aplikację.W większości aplikacji należy zwykle nie Czekaj na asynchroniczne czynności do wykonania.

  5. Tworzenie IThreadPoolTimer obiekt, który wygasa po upływie dwóch sekund.Użycie Callback funkcja służąca do tworzenia programu obsługi zdarzeń ( ABI::Windows::System::Threading::ITimerElapsedHandler obiektu).

    // 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);
    }
    
  6. Drukowanie wiadomości do konsoli i oczekiwania na wywołanie zwrotne czasomierza zakończyć.Wszystkie ComPtr i obiekty RAII pozostawić zakres i są automatycznie zwalniane.

    // 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.
    

Oto przykład kompletne:

// 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.
*/

Kompilowanie kodu

Aby skompilować kod, skopiuj go a następnie wkleić go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie wrl zużywają async.cpp , a następnie uruchomić następujące polecenie w oknie wiersza polecenia programu Visual Studio.

cl.exe wrl-consume-async.cpp runtimeobject.lib

Przykład: Praca z wątek tła

W poniższych krokach uruchomić wątku roboczego oraz zdefiniować akcję wykonywaną przez tego wątku.Pełny przykład poniżej.

PoradaPorada

Ten przykład ilustruje sposób pracy z ABI::Windows::Foundation::IAsyncAction interfejsu.Ten wzór można zastosować do dowolnego interfejsu, który implementuje IAsyncInfo: IAsyncAction, IAsyncActionWithProgress, IAsyncOperation, i IAsyncOperationWithProgress.

  1. Obejmują (#include) wszystkie wymagane Środowisko wykonawcze systemu Windows, WRL, lub standard C++ library nagłówków.

    #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 oświadcza, typy, które są zobowiązane do stosowania wątku roboczego.

    Firma Microsoft zaleca użycie using namespace w pliku cpp, aby zwiększyć czytelność kodu w dyrektywie.

  2. Inicjowanie Środowisko wykonawcze systemu Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Utworzyć fabryki aktywacji dla ABI::Windows::System::Threading::IThreadPoolStatics interfejsu.

    // 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);
    }
    
  4. Tworzenie zdarzenia obiektu, która synchronizuje zakończenia wątku roboczego do głównej aplikacji.

    // 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);
        }
    

    [!UWAGA]

    To zdarzenie jest wykazanie tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenia do zapewnienia, że operacji asynchronicznej zostanie zakończony przed zamyka aplikację.W większości aplikacji należy zwykle nie Czekaj na asynchroniczne czynności do wykonania.

  5. Wywołanie IThreadPoolStatics::RunAsync metoda tworzenia wątku roboczego.Użycie Callback funkcja, aby zdefiniować akcję.

    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 Funkcja jest zdefiniowana w kompletnym przykładzie, który następuje.

  6. Drukowanie wiadomości do konsoli i czekać na wątku do wykonania.Wszystkie ComPtr i obiekty RAII pozostawić zakres i są automatycznie zwalniane.

    // 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.
    

Oto przykład kompletne:

// 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.
*/

Kompilowanie kodu

Aby skompilować kod, skopiuj go a następnie wkleić go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie wrl zużywają asyncOp.cpp , a następnie uruchomić następujące polecenie w oknie wiersza polecenia programu Visual Studio.

cl.exe wrl-consume-asyncOp.cpp runtimeobject.lib

Zobacz też

Koncepcje

Biblioteka szablonów języka C++ środowiska wykonawczego systemu Windows (WRL)