Udostępnij za pośrednictwem


Porady: wykonywanie operacji asynchronicznych z użyciem biblioteki WRL

Ten dokument 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 podczas tworzenia obiektu timer określić się akcja asynchroniczna.Drugi przykład działa wątek roboczy tła.W tym przykładzie przedstawiono sposób pracy z Środowisko wykonawcze systemu Windows metoda, która zwraca IAsyncInfo interfejsu.Wywołania zwrotnego funkcja jest ważną częścią zarówno przykłady, ponieważ umożliwia im określić program obsługi zdarzeń do przetworzenia wyników operacji asynchronicznych.

Na przykład bardziej podstawową, która tworzy instancję 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 Lambda wyrażenia w języku C++.

Przykład: Praca z czasomierzem

Następujące kroki uruchomić asynchronicznego zegara i czekać na czasomierzu.Poniżej przedstawiono prosty przykład kompletne.

Informacje dotyczące przestrogiPrzestroga

Chociaż zazwyczaj używa się WRL w Windows Store aplikacji, w tym przykładzie używa aplikacji konsoli jako ilustracja.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 aplikacji Win32 i COM dla magazynu systemu Windows.

  1. Obejmują (#include) wszystkie wymagane Środowisko wykonawcze systemu Windows, WRL, lub standardowych nagłówków biblioteka języka 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 oświadcza, typy, które są zobowiązane do stosowania asynchronicznego czasomierza.

    Firma Microsoft zaleca, aby wykorzystać using namespace w dyrektywie w pliku .cpp, aby kod był bardziej czytelny.

  2. Zainicjuj Ś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 Jest ciągiem, który jest udostępniany przez Środowisko wykonawcze systemu Windows i zawiera nazwę klasy wymagane runtime.

  4. Tworzenie zdarzenie obiektu, która synchronizuje wywołania zwrotnego czasomierza 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 demonstracyjne tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenie, aby zapewnić, że operacji asynchronicznej zostanie zakończony przed wyjściach aplikacji.W większości aplikacji należy zwykle nie czekać na na zakończenie operacji asynchronicznej.

  5. Tworzenie IThreadPoolTimer obiekt, który wygasa po dwóch sekundach.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 czekać na wywołania zwrotnego czasomierza zakończyć.Wszystkie ComPtr i RAII obiektów 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 kompletny przykład:

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

Hh973451.collapse_all(pl-pl,VS.110).gifKompilowanie kodu

Aby skompilować kod, skopiuj go i następnie wkleić go w projekcie programu Visual Studio lub wklej go w pliku o nazwie światowym laboratorium referencyjnym zużywają async.cpp a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi programu Visual Studio.

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

Przykład: Praca z wątek w tle

W poniższych krokach uruchomić wątku roboczego oraz zdefiniować akcję wykonywaną przez ten wątek.Poniżej przedstawiono prosty przykład kompletne.

PoradaPorada

Ten przykład demonstruje 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 standardowych nagłówków biblioteka języka 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 oświadcza, typy, które są zobowiązane do stosowania wątku roboczego.

    Firma Microsoft zaleca, aby wykorzystać using namespace w dyrektywie w pliku .cpp, aby kod był bardziej czytelny.

  2. Zainicjuj Ś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 zdarzenie obiektu, która synchronizuje zakończenie 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 demonstracyjne tylko jako część aplikacji konsoli.W tym przykładzie użyto zdarzenie, aby zapewnić, że operacji asynchronicznej zostanie zakończony przed wyjściach aplikacji.W większości aplikacji należy zwykle nie czekać na na zakończenie operacji asynchronicznej.

  5. Call IThreadPoolStatics::RunAsync metodę w celu utworzenia wątku roboczego.Użycie Callback funkcji, 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 następującym przykładzie pełną.

  6. Wydrukować wiadomość do konsoli i poczekaj, aż wątek, aby ukończyć.Wszystkie ComPtr i RAII obiektów 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 kompletny przykład:

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

Hh973451.collapse_all(pl-pl,VS.110).gifKompilowanie kodu

Aby skompilować kod, skopiuj go i następnie wkleić go w projekcie programu Visual Studio lub wklej go w pliku o nazwie światowym laboratorium referencyjnym zużywają asyncOp.cpp a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi 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)