C++新特性 协程

简介: 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代码实例:

#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. 协程函数本身必须是异步上下文(比如异步任务、生成器)或者包含了异步操作。

代码实例:

#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(): 返回异步操作结果的值。

代码实例:

#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

相关文章
|
2月前
|
C语言 C++ 开发者
深入探索C++:特性、代码实践及流程图解析
深入探索C++:特性、代码实践及流程图解析
|
9天前
|
编译器 C++ 开发者
C++一分钟之-C++20新特性:模块化编程
【6月更文挑战第27天】C++20引入模块化编程,缓解`#include`带来的编译时间长和头文件管理难题。模块由接口(`.cppm`)和实现(`.cpp`)组成,使用`import`导入。常见问题包括兼容性、设计不当、暴露私有细节和编译器支持。避免这些问题需分阶段迁移、合理设计、明确接口和关注编译器更新。示例展示了模块定义和使用,提升代码组织和维护性。随着编译器支持加强,模块化将成为C++标准的关键特性。
27 3
|
15天前
|
编译器 C语言 C++
C++一分钟之-C++11新特性:初始化列表
【6月更文挑战第21天】C++11的初始化列表增强语言表现力,简化对象构造,特别是在处理容器和数组时。它允许直接初始化成员变量,提升代码清晰度和性能。使用时要注意无默认构造函数可能导致编译错误,成员初始化顺序应与声明顺序一致,且在重载构造函数时避免歧义。利用编译器警告能帮助避免陷阱。初始化列表是高效编程的关键,但需谨慎使用。
25 2
|
3天前
|
数据安全/隐私保护 C++
|
6天前
|
调度 C++ 开发者
C++一分钟之-认识协程(coroutine)
【6月更文挑战第30天】C++20引入的协程提供了一种轻量级的控制流抽象,便于异步编程,减少了对回调和状态机的依赖。协程包括使用`co_await`、`co_return`、`co_yield`的函数,以及协程柄和awaiter来控制执行。它们适合异步IO、生成器和轻量级任务调度。常见问题包括与线程混淆、不当使用`co_await`和资源泄漏。例如,斐波那契生成器协程展示了如何生成序列。正确理解和使用协程能简化异步代码,但需注意生命周期管理。
16 4
|
10天前
|
安全 JavaScript 前端开发
C++一分钟之-C++17特性:结构化绑定
【6月更文挑战第26天】C++17引入了结构化绑定,简化了从聚合类型如`std::tuple`、`std::array`和自定义结构体中解构数据。它允许直接将复合数据类型的元素绑定到单独变量,提高代码可读性。例如,可以从`std::tuple`中直接解构并绑定到变量,无需`std::get`。结构化绑定适用于处理`std::tuple`、`std::pair`,自定义结构体,甚至在范围for循环中解构容器元素。注意,绑定顺序必须与元素顺序匹配,考虑是否使用`const`和`&`,以及谨慎处理匿名类型。通过实例展示了如何解构嵌套结构体和元组,结构化绑定提升了代码的简洁性和效率。
22 5
|
3天前
|
存储 安全 编译器
|
2月前
|
编译器 C语言 C++
C++的基本特性和语法
C++的基本特性和语法
19 1
|
2月前
|
自然语言处理 编译器 C语言
【C++】C++ 入门 — 命名空间,输入输出,函数新特性
本文章是我对C++学习的开始,很荣幸与大家一同进步。 首先我先介绍一下C++,C++是上个世纪为了解决软件危机所创立 的一项面向对象的编程语言(OOP思想)。
46 1
【C++】C++ 入门 — 命名空间,输入输出,函数新特性
|
19天前
|
C++
C++ 是一种面向对象的编程语言,它支持对象、类、继承、多态等面向对象的特性
C++ 是一种面向对象的编程语言,它支持对象、类、继承、多态等面向对象的特性