Kirim item kerja ke kumpulan utas

API Penting

Pelajari cara melakukan pekerjaan di utas terpisah dengan mengirimkan item kerja ke kumpulan utas. Gunakan ini untuk mempertahankan UI responsif saat masih menyelesaikan pekerjaan yang membutuhkan waktu yang nyata, dan gunakan untuk menyelesaikan beberapa tugas secara paralel.

Membuat dan mengirimkan item kerja

Buat item kerja dengan memanggil RunAsync. Berikan delegasi untuk melakukan pekerjaan (Anda dapat menggunakan lambda, atau fungsi delegasi). Perhatikan bahwa RunAsync mengembalikan objek IAsyncAction ; simpan objek ini untuk digunakan di langkah berikutnya.

Tiga versi RunAsync tersedia sehingga Anda dapat secara opsional menentukan prioritas item kerja, dan mengontrol apakah runAsync berjalan bersamaan dengan item kerja lainnya.

Contoh berikut membuat item kerja dan memasok lambda untuk melakukan pekerjaan:

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

Mengikuti panggilan ke RunAsync, item kerja diantrekan oleh kumpulan utas dan berjalan saat utas tersedia. Item kerja kumpulan alur berjalan secara asinkron dan dapat berjalan dalam urutan apa pun, jadi pastikan item kerja Anda berfungsi secara independen.

Perhatikan bahwa item kerja memeriksa properti IAsyncInfo.Status, dan berhenti jika item kerja dibatalkan.

Tangani penyelesaian item kerja

Berikan handler penyelesaian dengan mengatur properti IAsyncAction.Completed dari item kerja. Berikan delegasi (Anda dapat menggunakan fungsi lambda atau delegasi) untuk menangani penyelesaian item kerja. Misalnya, gunakan DispatcherQueue.TryEnqueue untuk mengakses utas UI dan menampilkan hasilnya.

Contoh berikut memperbarui UI dengan hasil item kerja yang dikirimkan di langkah 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);
    });
});

Perhatikan bahwa handler penyelesaian memeriksa apakah item kerja dibatalkan sebelum mengirimkan pembaruan UI.

Ringkasan dan langkah berikutnya

Anda dapat mempelajari lebih lanjut tentang contoh threading SDK Aplikasi Windows di GitHub.