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.
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.Windows Çalışma Zamanı başlatın.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
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.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.
İki saniye sonra süresi dolan bir
IThreadPoolTimer
nesne oluşturun. olay işleyicisiniCallback
(birABI::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); }
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 IAsyncInfo
herhangi bir arabirime uygulayabilirsiniz: IAsyncAction
, IAsyncActionWithProgress
, IAsyncOperation
ve IAsyncOperationWithProgress
.
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.Windows Çalışma Zamanı başlatın.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
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); }
Ç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.
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.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