【CPP】协程

文章目录

    • **C++20 协程的基础概念:**
        • 1. **什么是协程?**
        • 2. **协程的三个核心概念:**
        • 3. **协程与线程的对比:**
    • 协程句柄
      • **`coroutine_handle` 的作用:**
      • ⚙️ **`coroutine_handle` 的定义与用法:**
        • **基本定义:**
      • **协程句柄的基本使用:**
        • **输出:**
      • ⚙️ **协程句柄的核心操作:**
      • **总结:**
    • ⚙️ **C++ 协程的语法:**
      • **代码解析:**
        • 1. **`MyTask` 和 `promise_type`**
        • 2. **协程的挂起与恢复**
        • 3. **输出:**
      • **常用的协程特性和标准库:**
        • 1. **`std::future` 和 `std::async`**
        • 2. **`co_await` 和 `co_return`**
        • 3. **`std::suspend_always` 和 `std::suspend_never`**
      • **协程的实际应用场景:**
      • **总结:**

在 C++20 中,协程(coroutines)是一个重磅新特性,它简化了异步编程的方式。你不再需要使用传统的回调函数、状态机或线程池来处理异步操作。通过协程,你可以像写同步代码一样写异步代码,同时保留异步执行的优势。


C++20 协程的基础概念:

1. 什么是协程?

协程是一种特殊的函数,它可以在执行过程中暂停,并且能够在之后的某个时刻继续执行。与线程不同,协程并不会真正地“脱离”当前的线程,它只是让控制流从一个函数流转到另一个地方,然后再回来。这个过程是 轻量级非阻塞 的。

2. 协程的三个核心概念:
  • 协程句柄(Coroutine Handle):用于管理协程的状态。
  • co_await:用于挂起协程并等待某个操作完成,类似于 await 在其他语言中的表现。
  • co_return:用于从协程中返回结果并结束协程的执行。
3. 协程与线程的对比:
  • 线程:独立的执行单元,具有自己的栈空间,需要系统调度。
  • 协程:轻量级线程,由编译器调度,不需要独立栈。

协程句柄

coroutine_handle 是 C++ 协程中的一个非常重要的类型,它用来管理协程的生命周期和状态。通过它,你可以控制协程的执行、挂起和恢复。


coroutine_handle 的作用:

在 C++ 协程中,每个协程都有一个 promise_type 结构体,它定义了协程的返回值和生命周期管理。coroutine_handle 则是与该 promise_type 类型关联的句柄,主要用于以下几个方面:

  1. 管理协程的生命周期

    • coroutine_handle 是一个与特定协程实例关联的句柄,通过它可以管理协程的暂停、恢复和销毁。
  2. 恢复协程执行

    • 通过 coroutine_handle 可以恢复已挂起的协程执行。协程挂起时,它的状态会被保存,直到 resume() 被调用。
  3. 销毁协程

    • 协程完成执行后,可以通过 coroutine_handle 来销毁协程对象,释放其资源。

⚙️ coroutine_handle 的定义与用法:

在协程中,promise_type 是协程返回的类型,它定义了协程的开始、结束以及如何处理异常等。而 coroutine_handle 是一个专门的句柄,负责管理协程的执行。它通过与 promise_type 结合,允许外部控制协程的流程。

基本定义:
struct promise_type {
    MyTask get_return_object() {
        return MyTask{handle_type::from_promise(*this)};
    }

    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }

    void return_void() {}
    void unhandled_exception() { std::exit(1); }
};

using handle_type = std::coroutine_handle<promise_type>;
  • std::coroutine_handle:是一个模板类,promise_type 是协程中的 promise 类型,协程的生命周期和状态通过它来管理。
  • get_return_object():该方法返回协程对象,创建并返回一个 MyTask 对象,协程会通过 std::coroutine_handle 来控制。
  • initial_suspend()final_suspend():分别控制协程的初始挂起和最终挂起行为。

协程句柄的基本使用:

#include 
#include 
#include 

struct MyTask {
    struct promise_type;  // 声明 promise_type
    using handle_type = std::coroutine_handle<promise_type>;

    MyTask(handle_type h) : coro(h) {}
    ~MyTask() { coro.destroy(); }

    handle_type coro;
};

struct MyTask::promise_type {
    MyTask get_return_object() {
        return MyTask{handle_type::from_promise(*this)};
    }

    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }

    void return_void() {}

    void unhandled_exception() {
        std::exit(1);  // 如果发生异常,退出
    }
};

MyTask my_coroutine() {
    std::cout << "Start of coroutine\n";
    co_await std::suspend_always{};  // 挂起协程
    std::cout << "End of coroutine\n";
}

int main() {
    auto task = my_coroutine();  // 调用协程
    std::cout << "Before coroutine resume\n";
    task.coro.resume();  // 恢复协程
    std::cout << "After coroutine resume\n";
    return 0;
}
输出:
Before coroutine resume
Start of coroutine
After coroutine resume
End of coroutine

⚙️ 协程句柄的核心操作:

  1. coroutine_handle::resume()

    • 恢复协程的执行。如果协程被挂起,可以通过 resume() 恢复它。
  2. coroutine_handle::destroy()

    • 销毁协程并释放相关资源。当协程执行完成后,可以调用 destroy() 来销毁协程对象。
  3. coroutine_handle::from_promise(promise_type&)

    • 通过 promise_type 创建协程句柄。promise_type 是定义协程返回值的类型,它负责处理协程的结果。

总结:

  • coroutine_handle 是 C++ 协程的核心,它帮助你管理协程的生命周期和状态,允许你暂停、恢复和销毁协程。
  • 它是与 promise_type 紧密配合的,promise_type 定义了协程的行为,而 coroutine_handle 则管理协程的执行。
  • 协程句柄为你提供了一种轻量级、简洁的方式来控制协程流程,避免了传统异步编程中常见的回调地狱。

理解并熟练使用协程句柄将大大提升你编写高效异步代码的能力,值得深入掌握!

⚙️ C++ 协程的语法:

#include 
#include 
#include 

struct MyTask {
    struct promise_type;  // 声明 promise_type
    using handle_type = std::coroutine_handle<promise_type>;

    MyTask(handle_type h) : coro(h) {}
    ~MyTask() { coro.destroy(); }

    handle_type coro;
};

struct MyTask::promise_type {
    MyTask get_return_object() {
        return MyTask{handle_type::from_promise(*this)};
    }

    std::suspend_never initial_suspend() { return {}; }  // 初始挂起
    std::suspend_never final_suspend() noexcept { return {}; }  // 最终挂起

    void return_void() {}  // 协程返回

    // 异常处理
    void unhandled_exception() {
        std::exit(1);  // 如果发生异常,退出
    }
};

MyTask my_coroutine() {
    std::cout << "Start of coroutine\n";
    co_await std::suspend_always{};  // 挂起协程
    std::cout << "End of coroutine\n";
}

int main() {
    auto task = my_coroutine();  // 调用协程
    std::cout << "Before coroutine resume\n";
    task.coro.resume();  // 恢复协程
    std::cout << "After coroutine resume\n";
    return 0;
}

代码解析:

1. MyTaskpromise_type
  • promise_type:是一个特殊结构体,协程的生命周期由它管理。get_return_object 创建并返回协程对象。
  • co_await:用于挂起协程,这里的 std::suspend_always{} 表示协程将在该点暂停,直到调用 resume() 恢复执行。
2. 协程的挂起与恢复
  • 在调用 co_await 后,协程会挂起,直到通过调用 coro.resume() 来恢复它的执行。
  • initial_suspend()final_suspend() 控制协程何时开始和结束。
3. 输出:
Before coroutine resume
Start of coroutine
After coroutine resume
End of coroutine

常用的协程特性和标准库:

1. std::futurestd::async

C++20 协程可以与标准库的异步功能(如 std::futurestd::async)结合使用,能够让协程变得更加易于使用。例如,使用 co_await 来等待 std::future

#include 
#include 
#include 

std::future<int> async_task() {
    co_return 42;  // 协程返回一个值
}

int main() {
    auto result = async_task();
    std::cout << "Result from coroutine: " << result.get() << "\n";
    return 0;
}
2. co_awaitco_return
  • co_await:协程挂起并等待某个操作(如异步任务的结果)。
  • co_return:返回协程的结果。
3. std::suspend_alwaysstd::suspend_never
  • std::suspend_always:协程总是会挂起。
  • std::suspend_never:协程永远不会挂起,直接执行。

协程的实际应用场景:

  1. 异步 I/O 操作:
    协程可以使得异步 I/O 操作变得像同步操作一样书写,避免回调地狱。

  2. 任务调度和并发:
    在多任务并发处理时,协程提供了一种更加直观且易于管理的方式来切换任务,减少了线程的开销。

  3. 网络编程:
    协程在网络请求处理等需要等待的场景中,能够极大简化代码结构,并提高性能。


总结:

C++20 协程将异步编程推向了一个全新的高度,它的优势在于:

  • 简洁性:通过协程,你可以像同步代码一样编写异步操作。
  • 效率:与传统的多线程相比,协程轻量得多,能够高效地切换上下文。
  • 灵活性:协程能够与标准库功能(如 std::future)和其他异步库无缝配合,提升编程体验。

虽然 C++ 协程的学习曲线稍微陡峭一些,但它带来的编程便利性无疑是值得掌握的!

你可能感兴趣的:(遣返回家的C家家,服务器,数据库,c++,开发语言)