Compartilhar via


Como executar operações assíncronas com WRL

Este documento mostra como usar Biblioteca em Tempo de Execução C++ do Tempo de Execução do Windows (WRL) para iniciar operações assíncronas e executar o trabalho quando as operações concluírem.

Este documento mostra dois exemplos.O primeiro exemplo inicia um timer assíncrona e espera o timer para expirar.Nesse exemplo, você especifica a ação assíncrona quando você cria o objeto timer.O segundo exemplo reproduz um segmento de trabalho em segundo plano.Este exemplo mostra como trabalhar com um método de Tempo de Execução do Windows que retorna uma interface de IAsyncInfo .A função de Retorno de chamada é uma parte importante de dois exemplos porque o permite especificar um manipulador de eventos para processar os resultados das operações assíncronas.

Para um exemplo mais básico que cria uma instância do componente e recupere um valor de propriedade, consulte Como ativar e usar um componente de Tempo de Execução do Windows com WRL.

DicaDica

Esses exemplos usam expressões lambda para definir os retornos de chamada.Você também pode usar objetos de função (functors), ponteiros de função, ou objetos de std::function .Para obter mais informações sobre expressões lambda C++, consulte Expressões lambda C++.

Exemplo: Trabalhar com um timer

As seguintes etapas ligam um timer assíncrona e esperam o timer para expirar.O exemplo completo maneira.

Observação de cuidadoCuidado

Embora você normalmente usa WRL em um aplicativo de Windows Store , este exemplo usa um aplicativo de console para a ilustração.As funções como wprintf_s não estão disponíveis de um aplicativo de Windows Store .Para obter mais informações sobre tipos e das funções que você pode usar em um aplicativo de Windows Store , consulte Funções de CRT não suportadas com /ZW e O Win32 e COM para aplicativos da Windows Store.

  1. Inclua ()#includequalquer Tempo de Execução do Windowsnecessário, WRL, ou cabeçalhos padrão da biblioteca 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 declara os tipos que são necessários para usar um timer assíncrono.

    Recomendamos que você utiliza a política de using namespace no arquivo de .cpp para tornar o código mais legível.

  2. Inicializar Tempo de Execução do Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Crie uma fábrica de ativação para a interface de 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);
    }
    

    Os nomes totalmente qualificados dos usos de Tempo de Execução do Windows para identificar tipos.O parâmetro de RuntimeClass_Windows_System_Threading_ThreadPoolTimer é uma cadeia de caracteres que é fornecida por Tempo de Execução do Windows contendo o nome da classe necessário em tempo de execução.

  4. Crie um objeto de Evento que sincronize o retorno de chamada do timer ao aplicativo principal.

    // 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);
    }
    
    ObservaçãoObservação

    Este evento é para demonstração somente como parte de um aplicativo de console.Este exemplo usa o evento para garantir que uma operação de async terminar antes de sair do aplicativo.Na maioria dos aplicativos, você normalmente não espera operações de async para concluir.

  5. Crie um objeto de IThreadPoolTimer que expirou após dois segundos.Use a função de Callback para criar o manipulador de eventos (um objeto de 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);
    }
    
  6. Imprimir uma mensagem para o console e espere o retorno de chamada do timer para concluir.Qualquer ComPtr e objetos de RAII deixe o escopo e são liberados automaticamente.

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

Aqui está um exemplo completo:

// 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(pt-br,VS.110).gifCompilando o código

Para compilar o código, copie e cole em um projeto Visual Studio, ou cole em um arquivo denominado wrl-consume-async.cpp e execute o seguinte comando em uma janela de prompt de comando do Visual Studio.

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

Exemplo: Trabalhar com uma thread em segundo plano

As seguintes etapas início de um segmento de trabalho e definem a ação que é executada por aquele segmento.O exemplo completo maneira.

DicaDica

Este exemplo demonstra como trabalhar com a interface de ABI::Windows::Foundation::IAsyncAction .Você pode aplicar esse padrão para qualquer interface que implementar IAsyncInfo: IAsyncAction, IAsyncActionWithProgress, IAsyncOperation, e IAsyncOperationWithProgress.

  1. Inclua ()#includequalquer Tempo de Execução do Windowsnecessário, WRL, ou cabeçalhos padrão da biblioteca 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 declara os tipos que são necessários para usar um segmento de trabalho.

    Recomendamos que você utiliza a política de using namespace no arquivo de .cpp para tornar o código mais legível.

  2. Inicializar Tempo de Execução do Windows.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Crie uma fábrica de ativação para a interface de 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);
    }
    
  4. Crie um objeto de Evento que sincronize a conclusão da thread de trabalho para o aplicativo principal.

        // 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);
        }
    
    
    ObservaçãoObservação

    Este evento é para demonstração somente como parte de um aplicativo de console.Este exemplo usa o evento para garantir que uma operação de async terminar antes de sair do aplicativo.Na maioria dos aplicativos, você normalmente não espera operações de async para concluir.

  5. Chame o método de IThreadPoolStatics::RunAsync para criar um segmento de trabalho.Use a função de Callback para definir a ação.

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

    A função de IsPrime é definida no exemplo completo que segue.

  6. Imprimir uma mensagem para o console e espere o segmento para.Qualquer ComPtr e objetos de RAII deixe o escopo e são liberados automaticamente.

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

Aqui está um exemplo completo:

// 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(pt-br,VS.110).gifCompilando o código

Para compilar o código, copie e cole em um projeto Visual Studio, ou cole em um arquivo denominado wrl-consume-asyncOp.cpp e execute o seguinte comando em uma janela de prompt de comando do Visual Studio.

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

Consulte também

Conceitos

Biblioteca de Modelos C++ do Tempo de Execução do Windows (WRL)