协程coroutine

1、协程概念

协程是一种比函数更轻量的子程序,它可以在执行过程中挂起(yield),保存当前状态,然后在稍后从同一位置恢复执行。与线程不同,协程共享栈空间,切换成本低,非常适合处理高并发、IO密集型任务。

协程描述为一个函数的泛化(generalisation)。与普通函数相比,除了“调用”和“返回”操作外,它还有3个额外的操作 - “暂停”,“恢复”和“摧毁”。

2、协程使用场景

网络编程:协程非常适合处理网络请求、文件读写等,能够简化异步I/O操作。

游戏开发:在游戏开发中,协程可以用于处理游戏逻辑、动画和事件。

数据处理:协程可以用于处理大规模数据流,逐步生成和处理数据,如std::generator。

3、C++协程

协程关键组件

        一个函数的返回值类型如果是符合协程的规则的类型,那么这个函数就是一个协程(协程体)。而co_await、co_yield、co_return这些运算符在这种函数中使用,即这个协程中使用。

        符合协程的规则的类型称为协程函数~~  

  1. 协程体:使用co_await、co_return、co_yield关键字标记的特殊函数。
  2. 承诺对象(Promise):协程的状态对象,包含了协程的结果、暂停和恢复的逻辑。
  3. 协程句柄(Handle):启动协程的实体,如std::coroutine_handle。
  4. "协程函数"(Coroutine Functions):自定义promise_type实现协程句柄std::coroutine_handle <promise_type>,如generator、task 和 lazy。
  5. awaiter:实现了std::suspend_always、std::suspend_never或自定义等待行为的类,用于控制协程的挂起和恢复。
  • co_await:用于等待一个异步操作的完成。这个关键词被用于挂起当前协程,并等待另一个操作完成。“挂起”(suspend)这个术语在协程中指的是保存当前协程的状态,然后将控制权交给调用者(或者调度器)。"等待"指的是当前协程在此位置的执行需要一个操作的完成。
  • co_yield:用于生成一个值并暂停协程的执行。个关键词将一个值返回给协程的调用者,并挂起当前协程。如果我们把协程想象成一个可以多次返回的函数,那么 co_yield 就类似于 return,但它允许我们在返回后,再从它挂起的地方继续执行。
  • co_return:用于返回一个值并结束协程的执行。与 return 在普通函数中的作用相似,co_return 用于从协程中返回值。但不同的是,co_return 还表示了协程的结束。

coroutine_handle  promise_type

std::coroutine_handle 类模板是为我们实现协程的各种“魔法”提供支持的最底层的设施,其主要负责存储协程的句柄。它分为模板 std::coroutine_handle<Promise> 和模板特化 std::coroutine_handle<void> ,std::coroutine_handle<void> 可以简单理解为就是做了类型擦除的 std::coroutine_handle<Promise>

自定义promise_type实现std::coroutine_handle<promise_type>

using Handle = std::coroutine_handle<promise_type>;

C++协程代码实现

基本协程框架

vs上支持coroutine实现

#include<coroutine>
#include<iostream>

class Coro {
};

Coro myCoroutine() {
	std::cout << " coroutine !" << std::endl;
	co_return;
}

int main()
{
	auto co = myCoroutine();
	return 0;
}

可以根据提示写出定义一下内容:

//协程的返回类型:std::suspend_always 和 std::suspend_never:用于控制协程的暂停行为

#include<coroutine>
#include<iostream>

class Coro {
public:
	struct promise_type {
		std::suspend_never initial_suspend() {
			return{};
		}
		std::suspend_always final_suspend() noexcept {
			return{};
		}
		void unhandled_exception() {}

		Coro get_return_object() {
			return Coro{};
		}

		void return_void() {}
	};
	
};

Coro myCoroutine() {
	std::cout << " coroutine !" << std::endl;
	co_return;
}

int main()
{
	auto co = myCoroutine();
	return 0;
}

自定义promise_type实现std::coroutine_handle<promise_type>

#include<coroutine>
#include<iostream>

class Coro {
public:
	struct promise_type {
		std::suspend_never initial_suspend() {
			return{};
		}
		std::suspend_always final_suspend() noexcept {
			return{};
		}
		void unhandled_exception() {}

		Coro get_return_object() {
			return handle_type::from_promise(*this);
		}

		void return_void() {}
	};
	// 自定义promise_type实现std::coroutine_handle<promise_type>
	using handle_type = std::coroutine_handle<promise_type>;
	
	handle_type coh;

	Coro(handle_type h):coh(h) {}
	~Coro() {
		coh.destroy();
	}
};

Coro myCoroutine() {
	std::cout << " coroutine !" << std::endl;
	co_return;
}

int main()
{
	auto co = myCoroutine();
	return 0;
}

实现斐波那契数列

#include<coroutine>
#include<iostream>

class Fib {
public:
	struct promise_type {
		std::suspend_never initial_suspend() {
			return{};
		}
		std::suspend_always final_suspend() noexcept {
			return{};
		}
		void unhandled_exception() {}

		Fib get_return_object() {
			return handle_type::from_promise(*this);
		}

		void return_void() {}

		//定义co_yield,生成下一个值
		std::suspend_always yield_value(int v) {
			if (v == 0 || v == 1) {
				cur = 1;
			}
			else {
				int tmp = pre;
				pre = cur;
				cur = pre + tmp;
			}

			return {};
		}
		int pre = 1;
		int cur = 1;

	};
	// 自定义promise_type实现std::coroutine_handle<promise_type>
	using handle_type = std::coroutine_handle<promise_type>;

	handle_type coh;

	Fib(handle_type h) :coh(h) {}
	~Fib() {
		coh.destroy();
	}

	bool cur() {
		if (coh.done()) { return false; }
		std::cout << value() << std::endl;
		coh.resume();
		return !coh.done();
	}
	int value() {
		return coh.promise().cur;
	}
};

Fib fib(int n) {
	for (int i = 0; i <= n; i++) {
		co_yield i;
	}
}

int main()
{
	auto f = fib(12);
	while (f.cur()) {
	}
	return 0;
}

Generator:C++23支持

Awaiter(等待体)

根据 Awaitable 和 Awaiter 概念实现和定义运算符 co_await

Awaiter 类型是一种实现三个特殊方法的类型,它们被称为 co_await 表达式的一部分:await_ready,await_suspend和await_resume。

Awaitable 和 Awaiter 概念

Awaitable 接口指定控制 co_await 表达式语义的方法。当一个值为 co_await 时,代码被转换为对 awaitable 对象上的方法的一系列调用。它可以指定:是否暂停当前协程,暂停调度协程以便稍后恢复后执行一些逻辑,还有在协程恢复后执行一些逻辑以产生 co_await 表达式的结果。

co_await运算符是一个新的一元运算符,可以应用于一个值。例如:co_await someValue。

co_await 运算符只能在协程的上下文中使用。这有点语义重复,因为根据定义,任何包含 co_await 运算符的函数体都将被编译为协程。

支持 co_await 运算符的类型称为 Awaitable 类型。

template<typename P, typename T>
decltype(auto) get_awaitable(P& promise, T&& expr)
{
  if constexpr (has_any_await_transform_member_v<P>)
    return promise.await_transform(static_cast<T&&>(expr));
  else
    return static_cast<T&&>(expr);
}
 
template<typename Awaitable>
decltype(auto) get_awaiter(Awaitable&& awaitable)
{
  if constexpr (has_member_operator_co_await_v<Awaitable>)
    return static_cast<Awaitable&&>(awaitable).operator co_await();
  else if constexpr (has_non_member_operator_co_await_v<Awaitable&&>)
    return operator co_await(static_cast<Awaitable&&>(awaitable));
  else
    return static_cast<Awaitable&&>(awaitable);
}
定义 Awaiter 类型

首先,它需要知道它将等待哪个 async_manual_reset_event 的对象,因此它需要一个对这一事件和对应构造函数的应用来进行初始化。

它还需要充当 awaiter 值链表中的节点,因此它需要持有指向列表中下一个 awaiter 对象的指针。

它还需要存储正在执行 co_await 表达式的等待协程的coroutine_handle,以便在事件变为 'set' 状态时事件可以恢复协程。我们不关心协程的 promise 类型是什么,所以我们只使用 coroutine_handle <>(这是 coroutine_handle <void> 的简写)。

最后,它需要实现 Awaiter 接口,因此需要三种特殊方法:await_ready,await_suspend 和 await_resume。 如果我们不需要从 co_await 表达式返回一个值,因此 await_resume 可以返回 void。

#include <iostream>
#include <coroutine>
#include <thread>
#include <chrono>

struct Awaiter {
    bool await_ready() { return false; }
    void await_suspend(std::coroutine_handle<> h) {
        std::thread([h]() {
            std::this_thread::sleep_for(std::chrono::seconds(1));  
        h.resume();  // 恢复协程
            }).detach();
    }
    void await_resume() {}
};

struct Coroutine {
    struct promise_type {
        Coroutine get_return_object() {
            return Coroutine{ handle_type::from_promise(*this) };
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void unhandled_exception() { std::terminate(); }
        void return_void() {}
    };

    using handle_type = std::coroutine_handle<promise_type>;

    handle_type coro_handle;

    Coroutine(handle_type h) : coro_handle(h) {}
    ~Coroutine() { coro_handle.destroy(); }
};

Coroutine asyncTask() {
    std::cout << "Waiting for 1 second..." << std::endl;
    //std::suspend_always、std::suspend_never、自定义awaiter类
    co_await Awaiter();  
    //co_await std::suspend_always{};
    std::cout << "Done waiting!" << std::endl;
}

int main() {
    auto task = asyncTask();  // 创建协程
    std::this_thread::sleep_for(std::chrono::seconds(2));  // 等待协程完成
    //task.coro_handle.resume();
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值