Nasıl Yapılır: WRL Kullanarak Zaman Uyumsuz İşlemleri Tamamlama

Bu belgede, Windows Çalışma Zamanı C++ Şablon Kitaplığı'nın (WRL) zaman uyumsuz işlemleri başlatmak ve işlemler tamamlandığında iş gerçekleştirmek için nasıl kullanılacağı gösterilmektedir.

Bu belgede iki örnek gösterilmektedir. İlk örnek zaman uyumsuz bir süreölçer başlatır ve süreölçerin süresinin dolmasını bekler. Bu örnekte, zamanlayıcı nesnesini oluştururken zaman uyumsuz eylemi belirtirsiniz. İkinci örnek bir arka plan çalışan iş parçacığı çalıştırır. Bu örnek, arabirim döndüren IAsyncInfo bir Windows Çalışma Zamanı yöntemiyle nasıl çalışıldığını gösterir. Callback işlevi, zaman uyumsuz işlemlerin sonuçlarını işlemek için bir olay işleyicisi belirtmelerine olanak sağladığından her iki örneğin de önemli bir parçasıdır.

Bir bileşenin örneğini oluşturan ve özellik değeri alan daha temel bir örnek için bkz. Nasıl yapılır: Windows Çalışma Zamanı Bileşenini Etkinleştirme ve Kullanma.

İpucu

Bu örneklerde, geri çağırmaları tanımlamak için lambda ifadeleri kullanılır. İşlev nesnelerini (functors), işlev işaretçilerini veya std::function nesnelerini de kullanabilirsiniz. C++ lambda ifadeleri hakkında daha fazla bilgi için bkz . Lambda İfadeleri.

Örnek: Zamanlayıcı ile Çalışma

Aşağıdaki adımlar zaman uyumsuz bir süreölçer başlatır ve süreölçerin süresinin dolmasını bekler. Tam örnek aşağıda verilmiştir.

Uyarı

Genellikle bir Evrensel Windows Platformu (UWP) uygulamasında Windows Çalışma Zamanı C++ Şablon Kitaplığı'nı kullansanız da, bu örnekte çizim için bir konsol uygulaması kullanılır. gibi wprintf_s işlevler UWP uygulamasında kullanılamaz. UWP uygulamasında kullanabileceğiniz türler ve işlevler hakkında daha fazla bilgi için bkz. Evrensel Windows Platformu uygulamalarında desteklenmeyen CRT işlevleri ve UWP uygulamaları için Win32 ve COM.

  1. Gerekli tüm Windows Çalışma Zamanı, Windows Çalışma Zamanı C++ Şablon Kitaplığı veya C++ Standart Kitaplığı üst bilgilerini ekleyin (#include).

    #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 zaman uyumsuz zamanlayıcı kullanmak için gereken türleri bildirir.

    Kodu daha okunabilir hale getirmek için .cpp dosyanızdaki yönergesini kullanmanızı using namespace öneririz.

  2. Windows Çalışma Zamanı başlatın.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Arabirim için ABI::Windows::System::Threading::IThreadPoolTimer bir etkinleştirme fabrikası oluşturun.

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

    Windows Çalışma Zamanı türleri tanımlamak için tam adlar kullanır. RuntimeClass_Windows_System_Threading_ThreadPoolTimer parametresi, Windows Çalışma Zamanı tarafından sağlanan ve gerekli çalışma zamanı sınıf adını içeren bir dizedir.

  4. Zamanlayıcı geri çağırmasını ana uygulamayla eşitleyen bir Event nesnesi oluşturun.

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

    Not

    Bu olay yalnızca bir konsol uygulamasının parçası olarak gösterim amaçlıdır. Bu örnekte, uygulamadan çıkmadan önce zaman uyumsuz bir işlemin tamamlandığından emin olmak için olayı kullanılır. Çoğu uygulamada genellikle zaman uyumsuz işlemlerin tamamlanmasını beklemezsiniz.

  5. İki saniye sonra süresi dolan bir IThreadPoolTimer nesne oluşturun. olay işleyicisini Callback (bir ABI::Windows::System::Threading::ITimerElapsedHandler nesne) oluşturmak için işlevini kullanın.

    // 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. Konsola bir ileti yazdırın ve zamanlayıcı geri çağırma işleminin tamamlanmasını bekleyin. Tüm ComPtr ve RAII nesneleri kapsamı bırakır ve otomatik olarak serbest bırakılır.

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

Tam örnek aşağıda verilmiştir:

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

Kod Derleniyor

Kodu derlemek için kopyalayın ve visual studio projesine yapıştırın veya adlı wrl-consume-async.cpp bir dosyaya yapıştırın ve ardından visual studio komut istemi penceresinde aşağıdaki komutu çalıştırın.

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

Örnek: Arka Plan İş Parçacığıyla Çalışma

Aşağıdaki adımlar bir çalışan iş parçacığı başlatır ve bu iş parçacığı tarafından gerçekleştirilen eylemi tanımlar. Tam örnek aşağıda verilmiştir.

İpucu

Bu örnek, arabirimle ABI::Windows::Foundation::IAsyncAction nasıl çalış yapılacağını gösterir. Bu deseni uygulayan IAsyncInfoherhangi bir arabirime uygulayabilirsiniz: IAsyncAction, IAsyncActionWithProgress, IAsyncOperationve IAsyncOperationWithProgress.

  1. Gerekli tüm Windows Çalışma Zamanı, Windows Çalışma Zamanı C++ Şablon Kitaplığı veya C++ Standart Kitaplığı üst bilgilerini ekleyin (#include).

    #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, bir çalışan iş parçacığı kullanmak için gereken türleri bildirir.

    Kodu daha okunabilir hale getirmek için .cpp dosyanızdaki yönergesini kullanmanızı using namespace öneririz.

  2. Windows Çalışma Zamanı başlatın.

    // Initialize the Windows Runtime.
    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    if (FAILED(initialize))
    {
        return PrintError(__LINE__, initialize);
    }
    
  3. Arabirim için ABI::Windows::System::Threading::IThreadPoolStatics bir etkinleştirme fabrikası oluşturun.

    // 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. Çalışan iş parçacığının tamamlanmasını ana uygulamayla eşitleyen bir Event nesnesi oluşturun.

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

    Not

    Bu olay yalnızca bir konsol uygulamasının parçası olarak gösterim amaçlıdır. Bu örnekte, uygulamadan çıkmadan önce zaman uyumsuz bir işlemin tamamlandığından emin olmak için olayı kullanılır. Çoğu uygulamada genellikle zaman uyumsuz işlemlerin tamamlanmasını beklemezsiniz.

  5. IThreadPoolStatics::RunAsync Bir çalışan iş parçacığı oluşturmak için yöntemini çağırın. Callback Eylemi tanımlamak için işlevini kullanın.

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

    İşlev, IsPrime aşağıdaki tam örnekte tanımlanmıştır.

  6. Konsola bir ileti yazdırın ve iş parçacığının tamamlanmasını bekleyin. Tüm ComPtr ve RAII nesneleri kapsamı bırakır ve otomatik olarak serbest bırakılır.

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

Tam örnek aşağıda verilmiştir:

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

Kod Derleniyor

Kodu derlemek için kopyalayın ve visual studio projesine yapıştırın veya adlı wrl-consume-asyncOp.cpp bir dosyaya yapıştırın ve ardından visual studio komut istemi penceresinde aşağıdaki komutu çalıştırın.

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

Ayrıca bkz.

Windows Çalışma Zamanı C++ Şablon Kitaplığı (WRL)