重要 API
學會如何在獨立執行緒中工作,方法是將工作項目提交到執行緒池。 利用它維持響應式介面,同時完成明顯需要時間的工作,並同時完成多項任務。
建立並提交工作項目
透過呼叫 RunAsync 建立工作項目。 提供一個代理人來執行工作(你可以使用 lambda 或代理人函式)。 請注意 ,RunAsync 會回傳 一個 IAsyncAction 物件;將此物件儲存以供下一步使用。
RunAsync 有三個版本可供選擇,讓你可選擇性地指定工作項目的優先順序,並控制它是否與其他工作項目同時執行。
以下範例建立一個工作項目,並提供一個 lambda 來執行該工作:
// The nth prime number to find.
const uint n = 9999;
// Receives the result.
ulong nthPrime = 0;
// Simulates work by searching for the nth prime number. Uses a
// naive algorithm and counts 2 as the first prime number.
// Capture the DispatcherQueue before entering the background lambda.
var dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
IAsyncAction asyncAction = Windows.System.Threading.ThreadPool.RunAsync(
(workItem) =>
{
uint progress = 0; // For progress reporting.
uint primes = 0; // Number of primes found so far.
ulong i = 2; // Number iterator.
if ((n >= 0) && (n <= 2))
{
nthPrime = n;
return;
}
while (primes < (n - 1))
{
if (workItem.Status == AsyncStatus.Canceled)
{
break;
}
// Go to the next number.
i++;
// Check for prime.
bool prime = true;
for (uint j = 2; j < i; ++j)
{
if ((i % j) == 0)
{
prime = false;
break;
}
};
if (prime)
{
// Found another prime number.
primes++;
// Report progress at every 10 percent.
uint temp = progress;
progress = (uint)(10.0*primes/n);
if (progress != temp)
{
String updateString;
updateString = "Progress to " + n + "th prime: "
+ (10 * progress) + "%\n";
// Update the UI thread with the DispatcherQueue.
dispatcherQueue.TryEnqueue(
Microsoft.UI.Dispatching.DispatcherQueuePriority.High,
() => UpdateUI(updateString));
}
}
}
// Return the nth prime number.
nthPrime = i;
});
// A reference to the work item is cached so that we can trigger a
// cancellation when the user presses the Cancel button.
m_workItem = asyncAction;
// The nth prime number to find.
const unsigned int n{ 9999 };
// A shared pointer to the result.
// We use a shared pointer to keep the result alive until the
// work is done.
std::shared_ptr<unsigned long> nthPrime = std::make_shared<unsigned long>(0);
// Simulates work by searching for the nth prime number. Uses a
// naive algorithm and counts 2 as the first prime number.
// Capture the DispatcherQueue before entering the background lambda.
auto dispatcherQueue{ Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread() };
// A reference to the work item is cached so that we can trigger a
// cancellation when the user presses the Cancel button.
m_workItem = Windows::System::Threading::ThreadPool::RunAsync(
[=, strongThis = get_strong()](Windows::Foundation::IAsyncAction const& workItem)
{
unsigned int progress = 0; // For progress reporting.
unsigned int primes = 0; // Number of primes found so far.
unsigned long int i = 2; // Number iterator.
if ((n >= 0) && (n <= 2))
{
*nthPrime = n;
return;
}
while (primes < (n - 1))
{
if (workItem.Status() == Windows::Foundation::AsyncStatus::Canceled)
{
break;
}
// Go to the next number.
i++;
// Check for prime.
bool prime = true;
for (unsigned int j = 2; j < i; ++j)
{
if ((i % j) == 0)
{
prime = false;
break;
}
};
if (prime)
{
// Found another prime number.
primes++;
// Report progress at every 10 percent.
unsigned int temp = progress;
progress = static_cast<unsigned int>(10.f*primes / n);
if (progress != temp)
{
std::wstringstream updateStream;
updateStream << L"Progress to " << n << L"th prime: " << (10 * progress) << std::endl;
std::wstring updateString = updateStream.str();
// Update the UI thread with the DispatcherQueue.
dispatcherQueue.TryEnqueue(
Microsoft::UI::Dispatching::DispatcherQueuePriority::High,
[strongThis, updateString]()
{
strongThis->UpdateUI(updateString);
});
}
}
}
// Return the nth prime number.
*nthPrime = i;
});
// The nth prime number to find.
const unsigned int n = 9999;
// A shared pointer to the result.
// We use a shared pointer to keep the result alive until the
// work is done.
std::shared_ptr<unsigned long> nthPrime = std::make_shared<unsigned long>(0);
// Simulates work by searching for the nth prime number. Uses a
// naive algorithm and counts 2 as the first prime number.
auto workItem = ref new Windows::System::Threading::WorkItemHandler(
[this, n, nthPrime](IAsyncAction^ workItem)
{
unsigned int progress = 0; // For progress reporting.
unsigned int primes = 0; // Number of primes found so far.
unsigned long int i = 2; // Number iterator.
if ((n >= 0) && (n <= 2))
{
*nthPrime = n;
return;
}
while (primes < (n - 1))
{
if (workItem->Status == AsyncStatus::Canceled)
{
break;
}
// Go to the next number.
i++;
// Check for prime.
bool prime = true;
for (unsigned int j = 2; j < i; ++j)
{
if ((i % j) == 0)
{
prime = false;
break;
}
};
if (prime)
{
// Found another prime number.
primes++;
// Report progress at every 10 percent.
unsigned int temp = progress;
progress = static_cast<unsigned int>(10.f*primes / n);
if (progress != temp)
{
String^ updateString;
updateString = "Progress to " + n + "th prime: "
+ (10 * progress).ToString() + "%\n";
// Update the UI thread with the CoreDispatcher.
CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
CoreDispatcherPriority::High,
ref new DispatchedHandler([this, updateString]()
{
UpdateUI(updateString);
}));
}
}
}
// Return the nth prime number.
*nthPrime = i;
});
auto asyncAction = ThreadPool::RunAsync(workItem);
// A reference to the work item is cached so that we can trigger a
// cancellation when the user presses the Cancel button.
m_workItem = asyncAction;
呼叫 RunAsync 後,工作項目會被執行緒池排隊,當執行緒可用時執行。 執行緒池的工作項目是非同步執行的,且可以任意順序執行,所以務必確保你的工作項目獨立運作。
請注意,工作項目會檢查 IAsyncInfo.Status 屬性,若工作項目被取消則會退出。
處理工作項目完成作業
透過設定工作項目的 IAsyncAction.Completed 屬性來提供完成處理程序。 提供一個代理(你可以使用 lambda 或代理函式)來處理工作項目的完成。 例如,使用 DispatcherQueue.TryEnqueue 存取 UI 執行緒並顯示結果。
以下範例更新介面,更新步驟 1 中提交的工作項目結果:
asyncAction.Completed = new AsyncActionCompletedHandler(
(IAsyncAction asyncInfo, AsyncStatus asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Canceled)
{
return;
}
String updateString;
updateString = "\n" + "The " + n + "th prime number is "
+ nthPrime + ".\n";
// Update the UI thread with the DispatcherQueue.
dispatcherQueue.TryEnqueue(
Microsoft.UI.Dispatching.DispatcherQueuePriority.High,
() => UpdateUI(updateString));
});
m_workItem.Completed(
[=, strongThis = get_strong()](Windows::Foundation::IAsyncAction const& asyncInfo, Windows::Foundation::AsyncStatus const& asyncStatus)
{
if (asyncStatus == Windows::Foundation::AsyncStatus::Canceled)
{
return;
}
std::wstringstream updateStream;
updateStream << std::endl << L"The " << n << L"th prime number is " << *nthPrime << std::endl;
std::wstring updateString = updateStream.str();
// Update the UI thread with the DispatcherQueue.
dispatcherQueue.TryEnqueue(
Microsoft::UI::Dispatching::DispatcherQueuePriority::High,
[strongThis, updateString]()
{
strongThis->UpdateUI(updateString);
});
});
請注意,完成處理程序會在發送 UI 更新前檢查工作項目是否已被取消。
摘要與後續步驟
你可以從 GitHub 上的 Windows 應用程式 SDK 執行緒範例中了解更多。