1 协程底层原理
1.1 协程帧的结构与内存布局
协程帧是协程实现的核心数据结构,承载着协程的完整执行状态:
cpp
struct coroutine_frame {
// 寄存器保存区域
void* resume_addr; // 恢复执行地址
void* destroy_addr; // 销毁函数地址
void* promise_ptr; // promise对象指针
// 局部变量存储
alignas(16) char local_vars[]; // 动态大小的局部变量存储
// 参数区域
// ... 函数参数副本
};
内存布局通常遵循:
- 高地址:promise对象和协程控制块
- 中地址:保存的寄存器上下文
- 低地址:局部变量和临时对象
1.2 状态机转换机制
编译器将协程函数转换为状态机模型:
cpp
// 原始协程函数
generator<int> coro_func() {
co_yield 1;
co_yield 2;
co_return 3;
}
// 转换后的状态机伪代码
struct __coro_state {
int __state = 0;
int __value;
bool move_next() {
switch(__state) {
case 0:
__value = 1;
__state = 1;
return true;
case 1:
__value = 2;
__state = 2;
return true;
case 2:
__value = 3;
__state = -1;
return false;
default:
return false;
}
}
};
1.3 编译器如何转换协程代码
编译器处理协程的关键步骤:
- 函数签名重写:识别协程关键字(co_await, co_yield, co_return)
- promise类型推导:根据返回类型确定promise_type
- 状态机生成:创建包含所有挂起点的状态机
- 内存分配:决定协程帧的分配策略(堆/栈/自定义)
2 自定义协程类型
2.1 实现Generator生成器
cpp
template<typename T>
class Generator {
public:
struct promise_type {
T value_;
std::exception_ptr exception_;
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() { exception_ = std::current_exception(); }
void return_void() noexcept {}
std::suspend_always yield_value(T value) {
value_ = std::move(value);
return {};
}
};
// 迭代器支持
class iterator {
public:
explicit iterator(std::coroutine_handle<promise_type> handle = nullptr)
: handle_(handle) {}
iterator& operator++() {
if (handle_ && !handle_.done()) {
handle_.resume();
if (handle_.done()) {
handle_ = nullptr;
}
}
return *this;
}
const T& operator*() const {
return handle_.promise().value_;
}
bool operator==(const iterator& other) const {
return handle_ == other.handle_;
}
bool operator!=(const iterator& other) const { return !(*this == other); }
private:
std::coroutine_handle<promise_type> handle_;
};
// 协程生命周期管理
explicit Generator(std::coroutine_handle<promise_type> handle) : handle_(handle) {}
~Generator() {
if (handle_) handle_.destroy();
}
Generator(Generator&& other) noexcept : handle_(other.handle_) {
other.handle_ = nullptr;
}
Generator& operator=(Generator&& other) noexcept {
if (this != &other) {
if (handle_) handle_.destroy();
handle_ = other.handle_;
other.handle_ = nullptr;
}
return *this;
}
iterator begin() {
if (handle_ && !handle_.done()) {
handle_.resume();
if (handle_.done()) return end();
}
return iterator{handle_};
}
iterator end() { return iterator{}; }
private:
std::coroutine_handle<promise_type> handle_;
};
2.2 实现异步Task
cpp
template<typename T>
class AsyncTask {
public:
struct promise_type {
std::variant<std::monostate, T, std::exception_ptr> result_;
std::coroutine_handle<> continuation_;
AsyncTask get_return_object() {
return AsyncTask{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend() noexcept { return {}; }
auto final_suspend() noexcept {
struct awaiter {
bool await_ready() noexcept { return false; }
std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
auto& promise = h.promise();
return promise.continuation_ ? promise.continuation_ : std::noop_coroutine();
}
void await_resume() noexcept {}
};
return awaiter{};
}
void unhandled_exception() {
result_.template emplace<2>(std::current_exception());
}
template<typename U>
void return_value(U&& value) {
result_.template emplace<1>(std::forward<U>(value));
}
// 协程链式调用支持
void set_continuation(std::coroutine_handle<> continuation) {
continuation_ = continuation;
}
};
// 异步结果获取
T get() {
if (!handle_.done()) {
handle_.resume();
}
auto& result = handle_.promise().result_;
if (result.index() == 2) {
std::rethrow_exception(std::get<2>(result));
}
return std::get<1>(result);
}
// 超时控制机制
template<typename Rep, typename Period>
std::optional<T> get_with_timeout(const std::chrono::duration<Rep, Period>& timeout) {
auto start = std::chrono::steady_clock::now();
while (!handle_.done()) {
if (std::chrono::steady_clock::now() - start > timeout) {
return std::nullopt;
}
handle_.resume();
}
return get();
}
// co_await支持,实现链式调用
bool await_ready() const { return handle_.done(); }
void await_suspend(std::coroutine_handle<> continuation) {
handle_.promise().set_continuation(continuation);
}
T await_resume() { return get(); }
private:
std::coroutine_handle<promise_type> handle_;
};
3 协程与错误处理
3.1 异常传播机制
协程中的异常处理遵循特殊规则:
cpp
generator<int> safe_coroutine() {
try {
co_yield 1;
throw std::runtime_error("test error");
co_yield 2;
} catch (const std::exception& e) {
// 异常会在协程恢复时重新抛出
std::cout << "Caught: " << e.what() << std::endl;
}
co_yield 3;
}
3.2 协程间的错误传递
cpp
AsyncTask<int> compute_value() {
co_return 42;
}
AsyncTask<std::string> process_data() {
try {
int value = co_await compute_value();
co_return "Success: " + std::to_string(value);
} catch (const std::exception& e) {
co_return "Error: " + std::string(e.what());
}
}
3.3 资源安全的RAII模式
cpp
class ScopedResource {
public:
ScopedResource() { resource_ = acquire_resource(); }
~ScopedResource() { release_resource(resource_); }
// 防止拷贝
ScopedResource(const ScopedResource&) = delete;
ScopedResource& operator=(const ScopedResource&) = delete;
private:
Resource* resource_;
};
AsyncTask<void> safe_operation() {
ScopedResource resource; // 协程挂起时资源保持安全
co_await some_async_operation();
// resource在协程销毁时自动清理
}
4 协程调度基础
4.1 单线程调度器实现
cpp
class SingleThreadScheduler {
public:
void schedule(std::coroutine_handle<> task) {
std::lock_guard lock(mutex_);
queue_.push(task);
cv_.notify_one();
}
void run() {
while (running_) {
std::coroutine_handle<> task;
{
std::unique_lock lock(mutex_);
cv_.wait(lock, [this] { return !queue_.empty() || !running_; });
if (!running_ && queue_.empty()) break;
task = queue_.front();
queue_.pop();
}
if (task && !task.done()) {
task.resume();
}
}
}
void stop() {
running_ = false;
cv_.notify_all();
}
private:
std::queue<std::coroutine_handle<>> queue_;
std::mutex mutex_;
std::condition_variable cv_;
bool running_ = true;
};
4.2 协程优先级调度
cpp
struct PrioritizedTask {
std::coroutine_handle<> task;
int priority;
bool operator<(const PrioritizedTask& other) const {
return priority < other.priority; // 更高优先级的值更小
}
};
class PriorityScheduler {
public:
void schedule(std::coroutine_handle<> task, int priority = 0) {
std::lock_guard lock(mutex_);
queue_.emplace(PrioritizedTask{task, priority});
cv_.notify_one();
}
void run() {
while (running_) {
PrioritizedTask ptask;
{
std::unique_lock lock(mutex_);
cv_.wait(lock, [this] { return !queue_.empty() || !running_; });
if (!running_ && queue_.empty()) break;
ptask = queue_.top();
queue_.pop();
}
if (ptask.task && !ptask.task.done()) {
ptask.task.resume();
}
}
}
private:
std::priority_queue<PrioritizedTask> queue_;
std::mutex mutex_;
std::condition_variable cv_;
bool running_ = true;
};
4.3 协程间通信机制
cpp
template<typename T>
class Channel {
public:
struct awaitable {
Channel& channel_;
T value_;
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h) {
channel_.receive_awaiter_ = h;
if (channel_.send_awaiter_) {
value_ = std::move(channel_.pending_value_);
channel_.send_awaiter_.resume();
channel_.send_awaiter_ = nullptr;
}
}
T await_resume() { return std::move(value_); }
};
struct sender_awaitable {
Channel& channel_;
T value_;
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h) {
channel_.send_awaiter_ = h;
channel_.pending_value_ = std::move(value_);
if (channel_.receive_awaiter_) {
channel_.receive_awaiter_.resume();
channel_.receive_awaiter_ = nullptr;
}
}
void await_resume() {}
};
sender_awaitable send(T value) {
return sender_awaitable{*this, std::move(value)};
}
awaitable receive() {
return awaitable{*this, T{}};
}
private:
std::coroutine_handle<> send_awaiter_;
std::coroutine_handle<> receive_awaiter_;
T pending_value_;
};
5 性能优化初探
5.1 避免不必要的协程切换
cpp
// 不良实践:频繁协程切换
AsyncTask<int> inefficient() {
for (int i = 0; i < 1000; ++i) {
co_await some_async_op(); // 每次循环都切换
}
}
// 优化:批量处理
AsyncTask<int> efficient() {
std::vector<AsyncTask<int>> tasks;
for (int i = 0; i < 1000; ++i) {
tasks.push_back(some_async_op());
}
co_await when_all(std::move(tasks)); // 一次性等待所有任务
}
5.2 内存池分配优化
cpp
class CoroutineMemoryPool {
static constexpr size_t POOL_SIZE = 1024;
static constexpr size_t FRAME_SIZE = 4096;
struct Block {
std::atomic<bool> used{false};
alignas(64) char data[FRAME_SIZE];
};
std::array<Block, POOL_SIZE> pool_;
public:
void* allocate(size_t size) {
for (auto& block : pool_) {
bool expected = false;
if (block.used.compare_exchange_strong(expected, true)) {
return block.data;
}
}
return ::operator new(size);
}
void deallocate(void* ptr) {
for (auto& block : pool_) {
if (block.data == ptr) {
block.used = false;
return;
}
}
::operator delete(ptr);
}
};
// 自定义分配器
template<typename Promise>
struct pool_allocator {
static void* operator new(size_t size) {
return get_pool().allocate(size);
}
static void operator delete(void* ptr, size_t size) {
get_pool().deallocate(ptr);
}
private:
static CoroutineMemoryPool& get_pool() {
static CoroutineMemoryPool pool;
return pool;
}
};
5.3 缓存友好的协程设计
cpp
// 优化协程帧布局
struct alignas(64) cache_friendly_frame {
// 高频访问数据放在一起
std::atomic<int> state;
void* resume_addr;
int priority;
// 填充缓存行
char padding[64 - sizeof(state) - sizeof(resume_addr) - sizeof(priority)];
// 低频访问数据
std::string debug_info;
std::chrono::steady_clock::time_point create_time;
};
// 批量处理协程
class CoroutineBatch {
std::vector<std::coroutine_handle<>> coroutines_;
public:
void add(std::coroutine_handle<> coro) {
coroutines_.push_back(coro);
}
void resume_all() {
// 连续内存访问,缓存友好
for (auto& coro : coroutines_) {
if (!coro.done()) {
coro.resume();
}
}
}
};
学习资源:
(1)管理教程
如果您对管理内容感兴趣,想要了解管理领域的精髓,掌握实战中的高效技巧与策略,不妨访问这个的页面:
在这里,您将定期收获我们精心准备的深度技术管理文章与独家实战教程,助力您在管理道路上不断前行。
(2)软件工程教程
如果您对软件工程的基本原理以及它们如何支持敏捷实践感兴趣,不妨访问这个的页面:
这里不仅涵盖了理论知识,如需求分析、设计模式、代码重构等,还包括了实际案例分析,帮助您更好地理解软件工程原则在现实世界中的运用。通过学习这些内容,您不仅可以提升个人技能,还能为团队带来更加高效的工作流程和质量保障。