【现代C++】协程的使用

在这里插入图片描述

协程是C++20引入的一项重要特性,它允许函数的执行被暂停并在之后恢复,非常适合用于异步编程、数据生产者/消费者模式、状态机等场景。协程的引入旨在提供一种更简洁和直观的方式来处理异步操作和非阻塞编程。以下是C++协程的关键概念和使用示例:

1. 协程基础

在C++中,协程是通过特殊的函数实现的,这些函数可以使用co_awaitco_returnco_yield关键字来暂停和恢复执行。

#include <coroutine>
#include <iostream>
#include <future>

std::future<void> simpleCoroutine() {
    std::cout << "Hello, ";
    co_await std::suspend_always{};
    std::cout << "World!" << std::endl;
    co_return;
}

void runSimpleCoroutine() {
    auto future = simpleCoroutine();
    future.get();  // 输出:Hello, World!
}

2. 使用co_yield生成值

协程可以使用co_yield生成一系列值,非常适合实现生成器模式。

#include <coroutine>
#include <iostream>
#include <vector>

struct Generator {
    struct promise_type {
        int current_value;
        std::suspend_always yield_value(int value) {
            current_value = value;
            return {};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        Generator get_return_object() { return Generator{this}; }
        void return_void() {}
        void unhandled_exception() { std::exit(1); }
    };

    std::coroutine_handle<promise_type> coro;

    Generator(promise_type* p) : coro(std::coroutine_handle<promise_type>::from_promise(*p)) {}
    ~Generator() { if (coro) coro.destroy(); }

    int getValue() { return coro.promise().current_value; }
    bool next() { coro.resume(); return !coro.done(); }
};

Generator generateNumbers() {
    for (int i = 0; i < 5; ++i) {
        co_yield i;
    }
}

void runGenerateNumbers() {
    auto gen = generateNumbers();
    while (gen.next()) {
        std::cout << gen.getValue() << " ";
    }
    // 输出:0 1 2 3 4
}

3. 使用co_await等待异步操作

co_await表达式可以暂停当前协程的执行,直到等待的对象准备就绪。

#include <coroutine>
#include <future>
#include <iostream>

std::future<int> asyncComputation() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    return std::async(std::launch::async, []() { return 42; });
}

std::future<void> awaitCoroutine() {
    int result = co_await asyncComputation();
    std::cout << "Result: " << result << std::endl;
    co_return;
}

void runAwaitCoroutine() {
    auto future = awaitCoroutine();
    future.get();  // 输出:Result: 42
}

4. 协程与异常处理

协程支持异常处理,你可以在协程内部使用try/catch块来处理异常。

#include <coroutine>
#include <iostream>
#include <stdexcept>

std::future<void> exceptionCoroutine() {
    try {
        throw std::runtime_error("Example exception");
        co_return;
    } catch (const std::exception& e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
}

void runExceptionCoroutine() {
    auto future = exceptionCoroutine();
    future.get();  // 输出:Caught exception: Example exception
}

通过这些示例可以看到C++协程如何用于不同的场景,它们提供了一种更直观和简洁的方式来处理异步操作、生成数据和编写复杂的控制流逻辑。

### 如何在C++使用协程实现串口通信 #### 使用背景 现代软件开发中,异步编程成为处理I/O密集型任务的关键技术之一。尤其对于串口通信这种典型的阻塞操作,传统的同步方法可能导致程序性能下降甚至死锁。随着C++20标准引入协程支持,开发者可以更高效地管理这些复杂的异步流程。 #### C++ 协程基础 C++中的协程是一种轻量级的执行单元,允许暂停和恢复其执行状态而无需切换到操作系统级别的线程[^1]。这使得它们非常适合用于诸如串口通信之类的长时间运行的任务,在不阻塞主线程的情况下等待数据传输完成。 #### 示例代码:基于协程的串口读写器 下面是一个简单的例子展示如何利用C++协程来构建一个非阻塞式的串口读取功能: ```cpp #include <coroutine> #include <iostream> #include <string> // 定义Promise类型 struct SerialReadOperation { struct promise_type { std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void unhandled_exception() {} auto get_return_object() { return SerialReadOperation{ std::coroutine_handle<promise_type>::from_promise(*this)}; } bool await_ready() const noexcept { return false; } void await_resume() const noexcept {} // Simulate serial port reading. char read_char_from_serial_port() { static int counter = 0; ++counter; if (counter % 5 != 0) return 'A' + rand()%26; else throw std::runtime_error("Simulated error"); } void await_suspend(std::coroutine_handle<> handle){ try { value_ = this->read_char_from_serial_port(); } catch(...) { exceptionPtr_ = std::current_exception(); } handle.resume(); } char value_; std::exception_ptr exceptionPtr_{nullptr}; }; explicit operator bool() const {return !promise_.exceptionPtr_;} char result(){ if(promise_.exceptionPtr_) { std::rethrow_exception(promise_.exceptionPtr_); } return promise_.value_; } private: std::coroutine_handle<promise_type> coroutineHandle_; public: ~SerialReadOperation(){if(coroutineHandle_) coroutineHandle_.destroy();} }; char ReadCharacterFromSerialPortWithCoroutine() { SerialReadOperation operation = co_await SerialReadOperation::promise_type{}; return operation.result(); } int main(){ while(true){ try{ char c = ReadCharacterFromSerialPortWithCoroutine(); std::cout << "Received character: " << c << '\n'; }catch(const std::exception& e){ std::cerr << "Error during reception: " << e.what() << "\nRetrying...\n"; } } } ``` 此示例模拟了一个从虚拟串口中逐字符读取的操作,并展示了错误处理逻辑以及如何通过协程使该过程变得非阻塞性[^2]。 #### 关键点解析 - **协程定义**: `SerialReadOperation` 是我们的自定义协程类,它包含了所有的控制流语义。 - **挂起/恢复机制**: 当协程遇到耗时操作(如实际硬件上的串口读取),它可以安全地中止当前活动并稍后再继续。 - **异常传播**: 如果发生任何问题(例如设备断开连接或超时),可以通过捕获抛出的标准库异常来进行适当反馈[^3]。 #### 总结 借助于C++20的新特性——协程,能够极大地简化像串口通讯这样原本复杂繁琐的过程。不仅提高了可维护性和扩展性,还减少了资源消耗,提升了整体系统的稳定性与效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值