协程:可暂停,可恢复,对异步/惰性计算很方便.用co_await暂停,co_yield暂停并返回一个值,co_return完成并返回值.
无栈协程可利用类似达夫设备,来搞定协程.即内部保存有状态.对称/非对称协程,类似星形与三角形之间关系.对称都平等,非对称,则每次都要往返.
协待后的表达式,必须有await_ready,await_suspend,await_resume三个函数.如总是挂起对象.1表示是否必须异步,2暂停前准备(有最重要的coroutine_handle(用来外部控制)参数),3,恢复协程..
承诺,根据协程返回值,用coroutine_traits取返回类型.

using T = coroutine_traits<return_type, Args...>;
using promise_type = T::promise_type;

取得返回类型.然后分配帧对象.
承诺类型必须有几个接口:get_return_object,initial_suspend,final_suspend,unhandled_exception,return_value,return_void函数.这是返回对象.
承诺对象内部控制协程,协程句柄外部控制.他们保存在帧上,相差不远(10h~20h).协程句柄内部有个:

struct _Resumable_frame_prefix {
    using _Resume_fn = void(__cdecl*)(void*);

    _Resume_fn _Fn;//恢复地址.
    uint16_t _Index;///索引点
    uint16_t _Flags;
};//有个帧前缀.
protected:
    _Resumable_frame_prefix* _Ptr = nullptr;

上面是coroutine_handle的部分.协程状态包括承诺对象,参数,临时变量和协程句柄里的_Resumable_frame_prefix

std::experimental::coroutine_handle<> g_h;

struct awaitee {
	bool await_ready() noexcept {return false;}
	void await_suspend(std::experimental::coroutine_handle<> h) noexcept {g_h = h;}
	void await_resume() noexcept {}
};
//协待,表达式,必须实现三个接口

template<typename ...Args>
return_object test_coroutine(Args... args) {
	co_await awaitee();co_return 1;
}

int main() {
	auto& ret = test_coroutine();
	if (ret.get_ret() == 0) {
		g_h.resume();
	}

	std::cout << "协程结束了."  << ret.get_ret() << std::endl;
	return 0;
}

其实就是一个,里面有承诺对象+协程句柄,两个相距距离就是承诺对象大小(但要16字节对齐).就是保存一个恢复点地址表,里面有个索引,每次就修改这个索引.从2开始,0与1留给取消操作的暂停与恢复点.汇编嘛,都是跳跳跳.
协程最关键就是暂停/恢复函数执行.通过编译器记录跳转点来实现.协程对象,只包含承诺对象、形参信息、临时变量、协程句柄.比回调多了协程句柄(1个函数指针+2个状态值),执行时,只计算一个地址,然后就跳转.所以不麻烦.
参考地址