Freigeben über


Gewusst wie: Abschließen asynchroner Vorgänge mit WRL

Dieses Dokument, wie Windows Runtime C++ Template Library () verwendet WRL um asynchrone Vorgänge zu starten und Arbeit ausführen wenn die vollständig Vorgänge.

Dieses Dokument enthält zwei Beispiele.Im ersten Beispiel startet einen asynchronen Zeitgeber und Wartung den Zeitgeber abläuft.In diesem Beispiel geben Sie die asynchrone Aktion angezeigt, wenn Sie das timer-Objekt erstellen.Das zweite Beispiel führt einen Hintergrundarbeitsthread aus.In diesem Beispiel wird gezeigt, wie mit einer Windows-Runtime-Methode funktioniert, die eine IAsyncInfo-Schnittstelle zurückgibt.Die Callback-Funktion ist ein wichtiger Teil beider Beispiele, da sie sie ermöglicht, einen Ereignishandler anzugeben, um die Ergebnisse der asynchronen Operation zu verarbeiten.

Ein grundlegenderes Beispiel, das eine Instanz dieser Komponente erstellt und einen Eigenschaftswert abruft, finden Sie unter Gewusst wie: Aktivieren und Verwenden einer Windows-Runtime-Komponente mit WRL.

TippTipp

Diese Beispiele verwenden Lambda-Ausdrücke, um die Rückrufe zu definieren.Sie können (Funktionselemente), Funktionsobjekte oder Funktionszeiger std::function-Objekte verwenden.Weitere Informationen zu Lambda-Ausdrücke (C++), finden Sie unter Lambda-Ausdrücke in C++.

Beispiel: Arbeiten mit einem Zeitgeber

Die folgenden Schritte stellen einen asynchronen Zeitgeber und warten, um den Zeitgeber abläuft.Im Folgenden finden Sie das vollständige Beispiel.

WarnhinweisVorsicht

Obwohl Sie in der Regel WRL in einer Windows Store-App, verwenden Sie dieses Beispiels eine Konsolen-App zur Veranschaulichung.Funktionen wie wprintf_s sind nicht von einer Windows Store-App verfügbar.Weitere Informationen zu den Typen und Funktionen, die Sie in einer Windows Store-App verwenden können, finden Sie unter CRT-Funktionen unterstützt nicht mit /ZW und Win32 und COM für Windows Store-Apps.

  1. Schließen Sie (#include) jede erforderliche Windows-Runtime, WRL oder Standard-C++-Bibliotheksheader ein.

    #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 deklariert die Typen, die erforderlich sind, um einen asynchronen Zeitgeber zu verwenden.

    Es wird empfohlen, die using namespace-Direktiven in der CPP-Datei verwenden, um den Code verständlicher zu gestalten.

  2. Initialisieren Sie Windows-Runtime.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Erstellen Sie eine Aktivierungsfactory für die ABI::Windows::System::Threading::IThreadPoolTimer-Schnittstelle erstellt.

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

    Die Windows-Runtime Verwendungsvollqualifizierten namen, von Typen identifizieren.Der RuntimeClass_Windows_System_Threading_ThreadPoolTimer-Parameter ist eine Zeichenfolge, die von Windows-Runtime bereitgestellt und den erforderlichen Ablaufklassennamen enthält.

  4. Erstellen Sie ein Event-Objekt, das den Zeitgeberrückruf der wichtigsten App synchronisiert.

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

    Dieses Ereignis ist für Demonstration nur als Teil einer Konsolen-App.In diesem Beispiel wird das - Ereignis, um sicherzustellen, dass eine asynchrone Operation vor der App-Beendigungen abgeschlossen hat.In den meisten App warten Sie normalerweise nicht auf asynchrone Vorgänge, um abzuschließen.

  5. Erstellen Sie ein - Objekt, das IThreadPoolTimer nach zwei Sekunden abläuft.Verwenden Sie die Callback-Funktion, um den - Ereignishandler ein ABI::Windows::System::Threading::ITimerElapsedHandler (- Objekt) zu erstellen.

    // 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. Drucken Sie eine Meldung an die Konsole und Warten auf den Zeitgeberrückruf, um abzuschließen.Alle ComPtr und RAII-Objekturlaub bewerten und automatisch freigegeben.

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

Hier ist das vollständige Beispiel:

// 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(de-de,VS.110).gifKompilieren des Codes

So kompilieren Sie den Code, ihn kopieren und in einem Visual Studio-Projekt dann einfügen, oder fügen Sie ihn in eine Datei einfügen, die wrl-consume-async.cpp namens und dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausgeführt.

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

Beispiel: Arbeiten mit einem Hintergrundthread

Die folgenden Schritte starten einen Arbeitsthread und definieren die Aktion, die von diesen Thread.Im Folgenden finden Sie das vollständige Beispiel.

TippTipp

In diesem Beispiel wird veranschaulicht, wie mit der ABI::Windows::Foundation::IAsyncAction-Schnittstelle funktioniert.Sie können dieses Muster zu jeder Schnittstelle anwenden, die IAsyncInfo implementiert: IAsyncAction, IAsyncActionWithProgress, IAsyncOperation und IAsyncOperationWithProgress.

  1. Schließen Sie (#include) jede erforderliche Windows-Runtime, WRL oder Standard-C++-Bibliotheksheader ein.

    #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 deklariert die Typen, die erforderlich sind, um einen Arbeitsthread zu verwenden.

    Es wird empfohlen, die using namespace-Direktiven in der CPP-Datei verwenden, um den Code verständlicher zu gestalten.

  2. Initialisieren Sie Windows-Runtime.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Erstellen Sie eine Aktivierungsfactory für die ABI::Windows::System::Threading::IThreadPoolStatics-Schnittstelle erstellt.

    // 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. Erstellen Sie ein - Objekt, das Event Abschluss des Arbeitsthreads der wichtigsten App synchronisiert.

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

    Dieses Ereignis ist für Demonstration nur als Teil einer Konsolen-App.In diesem Beispiel wird das - Ereignis, um sicherzustellen, dass eine asynchrone Operation vor der App-Beendigungen abgeschlossen hat.In den meisten App warten Sie normalerweise nicht auf asynchrone Vorgänge, um abzuschließen.

  5. Rufen Sie die IThreadPoolStatics::RunAsync-Methode auf, um einen Arbeitsthread zu erstellen.Verwenden Sie die Callback-Funktion, um die Aktion zu definieren.

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

    Die IsPrime-Funktion wird im vollständigen Beispiel definiert, das folgt.

  6. Drucken Sie eine Meldung an die Konsole und Warten auf den Thread, um abzuschließen.Alle ComPtr und RAII-Objekturlaub bewerten und automatisch freigegeben.

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

Hier ist das vollständige Beispiel:

// 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(de-de,VS.110).gifKompilieren des Codes

So kompilieren Sie den Code, ihn kopieren und in einem Visual Studio-Projekt dann einfügen, oder fügen Sie ihn in eine Datei einfügen, die wrl-consume-asyncOp.cpp namens und dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausgeführt.

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

Siehe auch

Konzepte

Windows Runtime C++ Template Library (WRL)