C++新特性 协程

本篇文章我们来讲述一下C++协程

协程(Coroutine)是一种能够挂起个恢复的函数过程 是一种轻量级的并发编程方式,也称为用户级线程。它与传统的线程(Thread)相比,具有更低的开销和更高的执行效率。 协程通常运用在异步调用中。

同步和异步 (拓展):同步是指线程要同时执行 如果没有两者没有同步 则需要线程A 等待线程B 或者主线程等待子线程 而异步编程就不需要线程的等待 但是也要注意线程争夺的问题

协程要讲清楚非常的抽象和复杂 我们直接从实际入手

代码实例:

大家看完以上代码结果可能会有一点懵 这是什么? 这是怎么回事?下面 让我们来分析一下代码:

大家观察这段代码就知道 main函数创建了一个进程 进程里面创建了一个主线程 然后执行每个函数就是子线程 先进入bar()函数 先执行call bar 然后执行before bar 经过挂起点然后挂起 这时候一个线程跳出了bar函数 到main里面 另一个线程执行fool函数 fool函数执行完以后 再回到bar 函数里面继续执行 这就是本代码的大概思路

下面我们来介绍一下 co_return 和co_await

co_return :co_return 是 C++20 中引入的关键字,用于在协程中返回结果或结束协程。它用于替代 return 关键字,在协程函数中表示返回值,并触发协程的完成。

co_return代码实例:

cpp 复制代码
#include <iostream>
#include <experimental/coroutine>

std::experimental::coroutine_handle<> myCoroutine;

void myTask() {
    std::cout << "Starting coroutine..." << std::endl;
    myCoroutine.resume(); // 启动协程
    std::cout << "Resuming execution..." << std::endl;
}

struct MyAwaitable {
    bool await_ready() const { return false; }
    void await_suspend(std::experimental::coroutine_handle<> handle) const {
        myCoroutine = handle; // 将当前协程保存起来
    }
    void await_resume() const {}
};

MyAwaitable asyncFunc() {
    std::cout << "Suspending execution..." << std::endl;
    co_await MyAwaitable{}; // 挂起协程,等待恢复
    std::cout << "Resumed execution..." << std::endl;
}

int main() {
    myTask();
    asyncFunc().await_resume();
    
    return 0;
}

在这个示例中,co_await 表达式会挂起 asyncFunc() 协程的执行,然后将控制权交还给 myTask() 协程。当我们调用 myCoroutine.resume() 时,asyncFunc() 的执行恢复,并继续执行后面的语句。

co_await介绍:

co_await 是 C++20 中引入的关键字,用于在协程中挂起当前的执行,并等待某个操作完成或者恢复执行。它是协程内部使用的一种语法,用于表示异步操作的等待。

在一个可暂停函数(协程)中,当遇到 co_await 表达式时,会发生以下几个步骤:

  1. 暂停当前协程的执行,并保存当前状态。
  2. 将控制权返回给调用方(如上层协程或者普通函数)。
  3. 在某个事件发生或者异步操作完成后,恢复之前保存的状态并继续执行。

具体来说,在使用 co_await 时需要满足两个条件:

  1. 表达式必须是一个可暂停的类型(也称为 Awaitable 类型),它要么定义了 bool await_ready() 方法来判断是否可以直接返回结果,要么定义了 void await_suspend(std::coroutine_handle<>) 方法和 void await_resume() 方法来进行挂起和恢复操作。
  2. 协程函数本身必须是异步上下文(比如异步任务、生成器)或者包含了异步操作。

代码实例:

cpp 复制代码
#include <iostream>
#include <experimental/coroutine>

struct MyAwaitable {
    bool await_ready() const { return false; }
    void await_suspend(std::experimental::coroutine_handle<> handle) const {
        std::cout << "Suspending coroutine..." << std::endl;
        handle.resume(); // 恢复协程的执行
    }
    void await_resume() const {}
};

std::experimental::suspend_always asyncFunc() {
    std::cout << "Starting coroutine..." << std::endl;
    co_await MyAwaitable{}; // 使用 co_await 挂起协程
    std::cout << "Resuming execution..." << std::endl;
}

int main() {
    auto coro = asyncFunc();
    coro.resume(); // 启动协程
    
    return 0;
}

代码总结:在这个示例中,MyAwaitable 是一个自定义的可暂停类型,它定义了 bool await_ready() 方法和 void await_suspend(std::coroutine_handle<>) 方法来控制协程的挂起和恢复。当我们调用 co_await MyAwaitable{} 时,协程会被挂起,并且打印出相应的消息。然后通过 handle.resume() 来恢复协程的执行。

co_await实现对象:

co_await 来实现协程等待一个对象时,该对象需要满足特定的条件和接口。在 C++ 中,需要实现以下几个关键的部分:

  1. 实现 awaitable 类型:这是一个自定义的类型,表示可以被协程等待的对象。它需要定义 await_ready()await_suspend()await_resume() 这三个成员函数。

    • await_ready(): 返回一个 bool 值,表示对象是否已经准备好(即不需要暂停协程)。如果对象已经可用,则返回 true;否则返回 false。
    • await_suspend(): 返回一个指定异步操作完成后应该如何恢复协程执行的 awaiter 类型。
    • await_resume(): 返回异步操作结果的值。

代码实例:

cpp 复制代码
#include <iostream>
#include <future>
#include <experimental/coroutine>

struct Awaitable {
    std::future<int> fut;

    bool await_ready() {
        return fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
    }

    void await_suspend(std::experimental::coroutine_handle<> handle) {
        fut.then([handle](std::future<int> f) mutable {
            // 异步操作完成后恢复协程执行
            handle.resume();
        });
    }

    int await_resume() {
        return fut.get();
    }
};

Awaitable makeAsyncRequest() {
    std::promise<int> p;
    auto fut = p.get_future();

    // 模拟异步操作
    std::thread([&p]() mutable {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        p.set_value(42);
    }).detach();

    return Awaitable{std::move(fut)};
}

std::experimental::suspend_always task() {
    auto result = co_await makeAsyncRequest(); // 等待异步操作完成,并获取结果
    std::cout << "Result: " << result << std::endl;
}

int main() {
   auto coro = task();
   coro.resume(); // 启动协程

   return 0;
}

总结:协程是应用于异步编程的一种方法 co_await函数用于当前的协程的挂起 这样可以更深层次的满足异步编程 要注意co_await函数的使用 co_return是用来返回结果和结束协程

好了 本篇内容就到这里 这篇文章可能有些难度 大家慢慢理解

在这里小编想向大家推荐一个课程: https://xxetb.xetslk.com/s/2PjJ3T

相关推荐
十年一梦实验室4 分钟前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0017 分钟前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
最爱番茄味13 分钟前
Python实例之函数基础打卡篇
开发语言·python
这是我5814 分钟前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc21 分钟前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很39 分钟前
C++ 集合 list 使用
c++
Oneforlove_twoforjob1 小时前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
engchina1 小时前
如何在 Python 中忽略烦人的警告?
开发语言·人工智能·python
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
诚丞成1 小时前
计算世界之安生:C++继承的文水和智慧(上)
开发语言·c++