Cara: Menyelesaikan Operasi Asinkron Menggunakan WRL
Dokumen ini menunjukkan cara menggunakan Windows Runtime C++ Template Library (WRL) untuk memulai operasi asinkron dan melakukan pekerjaan ketika operasi selesai.
Dokumen ini memperlihatkan dua contoh. Contoh pertama memulai timer asinkron dan menunggu timer kedaluwarsa. Dalam contoh ini, Anda menentukan tindakan asinkron saat membuat objek timer. Contoh kedua menjalankan utas pekerja latar belakang. Contoh ini menunjukkan cara bekerja dengan metode Windows Runtime yang mengembalikan IAsyncInfo
antarmuka. Fungsi Callback adalah bagian penting dari kedua contoh karena memungkinkan mereka menentukan penanganan aktivitas untuk memproses hasil operasi asinkron.
Untuk contoh yang lebih mendasar yang membuat instans komponen dan mengambil nilai properti, lihat Cara: Mengaktifkan dan Menggunakan Komponen Runtime Windows.
Tip
Contoh-contoh ini menggunakan ekspresi lambda untuk menentukan panggilan balik. Anda juga dapat menggunakan objek fungsi (functors), penunjuk fungsi, atau objek std::function . Untuk informasi selengkapnya tentang ekspresi lambda C++, lihat Ekspresi Lambda.
Contoh: Bekerja dengan Timer
Langkah-langkah berikut memulai timer asinkron dan menunggu timer kedaluwarsa. Contoh lengkapnya adalah sebagai berikut.
Peringatan
Meskipun Anda biasanya menggunakan Pustaka Templat Windows Runtime C++ di aplikasi Platform Windows Universal (UWP), contoh ini menggunakan aplikasi konsol untuk ilustrasi. Fungsi seperti wprintf_s
tidak tersedia dari aplikasi UWP. Untuk informasi selengkapnya tentang jenis dan fungsi yang dapat Anda gunakan di aplikasi UWP, lihat Fungsi CRT yang tidak didukung di aplikasi Platform Windows Universal dan Win32 dan COM untuk aplikasi UWP.
Sertakan (
#include
) Runtime Windows yang diperlukan, Pustaka Templat Windows Runtime C++, atau header Pustaka Standar 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
menyatakan jenis yang diperlukan untuk menggunakan timer asinkron.Kami menyarankan agar Anda menggunakan arahan
using namespace
dalam file .cpp Anda untuk membuat kode lebih mudah dibaca.Menginisialisasi Windows Runtime.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Buat pabrik aktivasi untuk
ABI::Windows::System::Threading::IThreadPoolTimer
antarmuka.// 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 Runtime menggunakan nama yang sepenuhnya memenuhi syarat untuk mengidentifikasi jenis. Parameter
RuntimeClass_Windows_System_Threading_ThreadPoolTimer
adalah string yang disediakan oleh Windows Runtime dan berisi nama kelas runtime yang diperlukan.Buat objek Peristiwa yang menyinkronkan panggilan balik timer ke aplikasi utama.
// 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); }
Catatan
Acara ini hanya untuk demonstrasi sebagai bagian dari aplikasi konsol. Contoh ini menggunakan peristiwa untuk memastikan bahwa operasi asinkron selesai sebelum aplikasi keluar. Di sebagian besar aplikasi, Anda biasanya tidak menunggu operasi asinkron selesai.
Buat
IThreadPoolTimer
objek yang kedaluwarsa setelah dua detik.Callback
Gunakan fungsi untuk membuat penanganan aktivitas (ABI::Windows::System::Threading::ITimerElapsedHandler
objek).// 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); }
Cetak pesan ke konsol dan tunggu hingga panggilan balik timer selesai. Semua
ComPtr
objek RAII dan meninggalkan cakupan dan dirilis secara otomatis.// 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.
Berikut adalah contoh lengkapnya:
// 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.
*/
Mengompilasi Kode
Untuk mengkompilasi kode, salin lalu tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama wrl-consume-async.cpp
lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.
cl.exe wrl-consume-async.cpp runtimeobject.lib
Contoh: Bekerja dengan Utas Latar Belakang
Langkah-langkah berikut memulai utas pekerja dan menentukan tindakan yang dilakukan oleh utas tersebut. Contoh lengkapnya adalah sebagai berikut.
Tip
Contoh ini menunjukkan cara bekerja dengan ABI::Windows::Foundation::IAsyncAction
antarmuka. Anda dapat menerapkan pola ini ke antarmuka apa pun yang mengimplementasikan : , , IAsyncActionWithProgress
IAsyncOperation
, dan IAsyncOperationWithProgress
. IAsyncAction
IAsyncInfo
Sertakan (
#include
) Runtime Windows yang diperlukan, Pustaka Templat Windows Runtime C++, atau header Pustaka Standar 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 mendeklarasikan jenis yang diperlukan untuk menggunakan utas pekerja.
Kami menyarankan agar Anda menggunakan direktif
using namespace
dalam file .cpp Anda untuk membuat kode lebih mudah dibaca.Menginisialisasi Windows Runtime.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Buat pabrik aktivasi untuk
ABI::Windows::System::Threading::IThreadPoolStatics
antarmuka.// 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); }
Buat objek Peristiwa yang menyinkronkan penyelesaian utas pekerja ke aplikasi utama.
// 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); }
Catatan
Acara ini hanya untuk demonstrasi sebagai bagian dari aplikasi konsol. Contoh ini menggunakan peristiwa untuk memastikan bahwa operasi asinkron selesai sebelum aplikasi keluar. Di sebagian besar aplikasi, Anda biasanya tidak menunggu operasi asinkron selesai.
IThreadPoolStatics::RunAsync
Panggil metode untuk membuat utas pekerja.Callback
Gunakan fungsi untuk menentukan tindakan.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); }
Fungsi
IsPrime
ini didefinisikan dalam contoh lengkap yang mengikuti.Cetak pesan ke konsol dan tunggu hingga utas selesai. Semua
ComPtr
objek RAII dan meninggalkan cakupan dan dirilis secara otomatis.// 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.
Berikut adalah contoh lengkapnya:
// 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.
*/
Mengompilasi Kode
Untuk mengkompilasi kode, salin lalu tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama wrl-consume-asyncOp.cpp
lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.
cl.exe wrl-consume-asyncOp.cpp runtimeobject.lib
Baca juga
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk