C++ 20标准协同程序(协程)基于编译器展开的 stackless 协程。

在查阅本文之前,请先查看本人的另外一篇关于协同程序切换的文献,这对于如何正确协同程序编程很有价值。

C/C++ 如何正确的切换协同程序?(基于协程的并行架构)-CSDN博客

我本人相当反对,在项目之中使用 C++ 20标准的 stackless 无栈协程,在上述博文之中明确提到了大体的原因是什么,并且 C/C++ 越新的标准越存在不可预计的编译风险性问题,目前基本可以确保稳定的 C++ 编译器标准为 C++ 17。

stackless 协程在 C/C++ 之中是 “switch 基于步骤的状态机切换” 协同程序展开结构,即每一次 MoveNext 切换到下一个工作流片。

这就像在 C# 之中,我们使用 C# 语言的迭代器来模拟实现协程一样,首先本人提供一个简单的协同程序切换的流程,就只使用 co_await 编译器关键字,我们就可以实现一个完整的协同程序切换流程。

以下述代码为例,将直接展示 C++ 20 标准提供的 stackless 程序编译器语法支援,即三个关键字的用法例子:co_await、co_yield、co_return

在只使用 co_await 关键字的情况下实现协同程序正确切换。

例子:

#include <iostream>
#include <coroutine>

struct MyTask {
    struct promise_type {
    public:
        MyTask                                  get_return_object() {
            return MyTask{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

    public:
        std::suspend_never                      initial_suspend() noexcept { return {}; }
        std::suspend_always                     final_suspend() noexcept { return {}; }
        void                                    return_void() noexcept {}
        void                                    unhandled_exception() noexcept {}
    };

public:
    explicit MyTask(std::coroutine_handle<promise_type> coro) noexcept : coroutine(coro) {}
    ~MyTask() noexcept {
        if (coroutine) {
            coroutine.destroy();
        }
    }

public:
    bool                                        await_ready() const noexcept { return false; }
    void                                        await_suspend(std::coroutine_handle<>) const noexcept {}
    void                                        await_resume() const noexcept {}

public:
    void                                        resume() noexcept {
        coroutine.resume();
    }

private:
    std::coroutine_handle<promise_type>         coroutine;
};

MyTask fork_stackless_coroutine() noexcept {
    std::cout << "协程,步一...\n";
    co_await std::suspend_always{};

    std::cout << "协程,步二.\n";
    co_await std::suspend_always{};

    std::cout << "协程,结束.\n";
}

int main() {
    MyTask task = fork_stackless_coroutine();

    std::cout << "主线程,步一...\n";
    task.resume();

    std::cout << "主线程,步二.\n";
    task.resume();

    std::cout << "主线程,结束.\n";
    return 0;
}

人们可以通过 co_return 关键字以促使 C++ 20 stackless 协程,可以返回数据。

例子:(协程返回值类型为:int)

#include <iostream>
#include <coroutine>

struct MyTask {
    struct promise_type {
    public:
        MyTask                                                      get_return_object() noexcept {
            return MyTask{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

    public:
        std::suspend_always                                         initial_suspend() noexcept { return {}; }
        std::suspend_always                                         final_suspend() noexcept { return {}; }

    public:
        void                                                        return_value(int value) {
            result = value;
        }
        void                                                        unhandled_exception() noexcept {}

    public:
        int                                                         result;
    };

public:
    explicit MyTask(std::coroutine_handle<promise_type> coro) noexcept : coroutine(coro) {}
    ~MyTask() {
        if (coroutine) {
            coroutine.destroy();
        }
    }

public:
    int                                                             result() const noexcept {
        return coroutine.promise().result;
    }
    void                                                            resume() noexcept {
        coroutine.resume();
    }

private:
    std::coroutine_handle<promise_type>                             coroutine;
};

MyTask fork_stackless_coroutine() noexcept {
    std::cout << "协程,结束返回" << std::endl;
    co_return 42;
}

int main() {
    MyTask task = fork_stackless_coroutine();

    task.resume();
    std::cout << "主线程,协程返回: " << task.result() << std::endl;
    return 0;
}

co_yield 迭代关键字在C#、之中的用法与 C++ 的用户几乎是一摸一样的用法,相对来说 C/C++,co_yield 关键更好用一点,co_await 跟 co_yield 都可以实现协同程序流程分片切换。

但区别是 co_yield 切换的分片,可以设置当前的迭代值,就像在C#当前,我们移动切换迭代器成功时,可以通过 Current 属性来获取当前的迭代值,co_await 不可以获得值。

#include <iostream>
#include <coroutine>

struct MyTask {
    struct promise_type {
    public:
        MyTask                                                      get_return_object() noexcept {
            return MyTask{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

    public:
        std::suspend_always                                         initial_suspend() noexcept { return {}; }
        std::suspend_always                                         final_suspend() noexcept { return {}; }

    public:
        std::suspend_always                                         yield_value(int value) noexcept {
            current_value = value;
            return {};
        }
        void                                                        return_void() noexcept {}
        void                                                        unhandled_exception() noexcept {}

    public:
        int                                                         current_value;
    };

public:
    explicit MyTask(std::coroutine_handle<promise_type> coro) noexcept : coroutine(coro) {}
    ~MyTask() {
        if (coroutine) {
            coroutine.destroy();
        }
    }

public:
    int                                                             current_value() const noexcept {
        return coroutine.promise().current_value;
    }
    bool                                                            move_next() noexcept {
        if (coroutine) {
            if (coroutine.done()) {
                return false;
            }

            coroutine.resume();
            return true;
        }

        return false;
    }

private:
    std::coroutine_handle<promise_type>                             coroutine;
};

MyTask fork_stackless_coroutine() noexcept {
    std::cout << "协程,开始:" << 100 << std::endl;
    co_yield 100;

    for (int i = 1; i <= 5; i++) {
        std::cout << "协程,步骤:" << i << std::endl;
        co_yield i;
    }
}

int main() {
    MyTask task = fork_stackless_coroutine();
    while (task.move_next()) {
        std::cout << "主线程,读值:" << task.current_value() << std::endl;
    }

    std::cout << "主线程,结束" << std::endl;
    return 0;
}

如何在 C++ 20 有栈协程之中在调用其它 stackless 协程?c20协程库高级应用,即:co_await、co_return 共同搭配使用。

#include <iostream>
#include <coroutine>

struct MyTask {
    struct promise_type {
    public:
        MyTask                                  get_return_object() {
            return MyTask{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

    public:
        std::suspend_never                      initial_suspend() noexcept { return {}; }
        std::suspend_always                     final_suspend() noexcept { return {}; }
        void                                    unhandled_exception() noexcept {}
        void                                    return_void() noexcept {}
    };

public:
    explicit MyTask(std::coroutine_handle<promise_type> coro) noexcept : coroutine(coro) {}
    ~MyTask() noexcept {
        if (coroutine) {
            coroutine.destroy();
        }
    }

public:
    bool                                        await_ready() const noexcept { return false; }
    void                                        await_suspend(std::coroutine_handle<> co) const noexcept {
        bool done = co.done();
        if (!done) {
            co.resume();
        }
    }
    void                                        await_resume() const noexcept {}

public:
    bool                                        move_next() noexcept {
        if (coroutine) {
            if (coroutine.done()) {
                return false;
            }

            coroutine.resume();
            return true;
        }

        return false;
    }

private:
    std::coroutine_handle<promise_type>         coroutine;
};

struct MyTaskInt {
    struct promise_type {
    public:
        MyTaskInt                               get_return_object() {
            return MyTaskInt{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

    public:
        std::suspend_never                      initial_suspend() noexcept {
            return {};
        }
        std::suspend_always                     final_suspend() noexcept {
            return {};
        }
        void                                    return_value(int value) {
            result = value;
        }
        void                                    unhandled_exception() noexcept {}

    public:
        int                                     result;
    };

public:
    explicit MyTaskInt(std::coroutine_handle<promise_type> coro) noexcept : coroutine(coro) {}
    ~MyTaskInt() noexcept {
        if (coroutine) {
            coroutine.destroy();
        }
    }

public:
    bool                                        await_ready() const noexcept { return false; }
    void                                        await_suspend(std::coroutine_handle<> co) const noexcept {
        bool done = co.done();
        if (!done) {
            co.resume();
        }
    }
    int                                         await_resume() const noexcept {
        return coroutine.promise().result;
    }

private:
    std::coroutine_handle<promise_type>         coroutine;
};

MyTaskInt fork_stackless_coroutine_return_100() noexcept {
    co_return 100;
}

MyTaskInt fork_stackless_coroutine_return_200() noexcept {
    int result = co_await fork_stackless_coroutine_return_100();
    result = result << 1;

    co_return result;
}

MyTask fork_stackless_coroutine_start() noexcept {
    int result = co_await fork_stackless_coroutine_return_100();
    std::cout << result << std::endl;

    result = co_await fork_stackless_coroutine_return_200();
    std::cout << result << std::endl;
}

int main() {
    MyTask task = fork_stackless_coroutine_start();
    while (task.move_next());
    return 0;
}

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值