Bagikan melalui


Sampel sumber penyelesaian

Catatan

Sebagai alternatif untuk kode sampel dalam topik ini, ada kode sumber untuk versi siap produksi dari implementasi sumber penyelesaian tugas dalam repositori GitHub cpp-async .

Topik ini menunjukkan bagaimana Anda dapat menulis dan menggunakan kelas sumber penyelesaian Anda sendiri, mirip dengan . TaskCompletionSource NET.

Kode sumber untuk sampel completion_source

Kode dalam daftar di bawah ini ditawarkan sebagai sampel. Tujuannya adalah untuk menggambarkan bagaimana Anda dapat menulis versi Anda sendiri. Misalnya, dukungan untuk pembatalan dan penyebaran kesalahan berada di luar cakupan sampel ini.

#include <winrt/base.h>
#include <windows.h>

template <typename T>
struct completion_source
{
    completion_source()
    {
        m_signal.attach(::CreateEvent(nullptr, true, false, nullptr));
    }

    void set(T const& value)
    {
        m_value = value;
        ::SetEvent(m_signal.get());
    }

    bool await_ready() const noexcept
    {
        return ::WaitForSingleObject(m_signal.get(), 0) == 0;
    }

    void await_suspend(std::experimental::coroutine_handle<> resume)
    {
        m_wait.attach(winrt::check_pointer(::CreateThreadpoolWait(callback, resume.address(), nullptr)));
        ::SetThreadpoolWait(m_wait.get(), m_signal.get(), nullptr);
    }

    T await_resume() const noexcept
    {
        return m_value;
    }

private:

    static void __stdcall callback(PTP_CALLBACK_INSTANCE, void* context, PTP_WAIT, TP_WAIT_RESULT) noexcept
    {
        std::experimental::coroutine_handle<>::from_address(context)();
    }

    struct wait_traits
    {
        using type = PTP_WAIT;

        static void close(type value) noexcept
        {
            ::CloseThreadpoolWait(value);
        }

        static constexpr type invalid() noexcept
        {
            return nullptr;
        }
    };

    winrt::handle m_signal;
    winrt::handle_type<wait_traits> m_wait;
    T m_value{};
};

Penyelesaian offload ke coroutine terpisah

Bagian ini menunjukkan satu kasus penggunaan untuk completion_source. Buat proyek baru di Visual Studio berdasarkan templat proyek Aplikasi Konsol Windows (C++/WinRT), dan tempelkan daftar kode berikut ke dalam main.cpp (memperluas definisi completion_source berdasarkan daftar di bagian sebelumnya).

// main.cpp
#include "pch.h"

#include <winrt/base.h>
#include <windows.h>

template <typename T>
struct completion_source
{
    ... // Paste the listing of completion_source here.
}

using namespace std::literals;
using namespace winrt;
using namespace Windows::Foundation;

fire_and_forget CompleteAfterFiveSecondsAsync(completion_source<bool>& completionSource)
{
    co_await 5s;
    completionSource.set(true);
}

IAsyncAction CompletionSourceExample1Async()
{
    completion_source<bool> completionSource;
    CompleteAfterFiveSecondsAsync(completionSource);
    co_await completionSource;
}

int main()
{
    auto asyncAction { CompletionSourceExample1Async() };
    puts("waiting");
    asyncAction.get();
    puts("done");
}

Merangkum completion_source di kelas, dan mengembalikan nilai

Dalam contoh berikutnya, kelas Aplikasi sederhana digunakan untuk merangkum completion_source, dan mengembalikan nilai saat selesai. Buat proyek baru di Visual Studio berdasarkan templat proyek Aplikasi Konsol Windows (C++/WinRT), dan tempelkan daftar kode berikut ke dalam main.cpp (memperluas definisi completion_source berdasarkan daftar di bagian sebelumnya).

// main.cpp
#include "pch.h"

#include <winrt/base.h>
#include <windows.h>

template <typename T>
struct completion_source
{
    ... // Paste the listing of completion_source here.
}

using namespace std::literals;
using namespace winrt;
using namespace Windows::Foundation;

struct App
{
    completion_source<winrt::hstring> m_completionSource;

    IAsyncOperation<winrt::hstring> CompletionSourceExample2Async()
    {
        co_return co_await m_completionSource;
    }

    winrt::fire_and_forget CompleteAfterFiveSecondsAsync()
    {
        co_await 5s;
        m_completionSource.set(L"Hello, World!");
    }
};

int main()
{
    App app;
    auto asyncAction{ app.CompletionSourceExample2Async() };
    app.CompleteAfterFiveSecondsAsync();
    puts("waiting");
    auto message = asyncAction.get();
    printf("%ls\n", message.c_str());
}