You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何`final_suspend`先于`await_suspend`调用?同步协程问题咨询

协程同步返回时final_suspend先于await_suspend执行的问题

现象说明

原本代码正常执行时,输出如下,最终返回42:

0x600002aa01c0 initial_suspend
0x6000031a02a0 initial_suspend
0x6000031a02a0 await_ready
0x6000031a02a0 await_suspend (precursor = 0x600002aa01c0)
0x6000031a02a0 final_suspend
0x6000031a02a0 await_resume
0x600002aa01c0 final_suspend
Result: 42

但注释掉bar()函数中的co_await next_tick()行(使bar变为无任何co_await调用的同步返回函数)后,输出变为:

0x6000008d81c0 initial_suspend
0x6000013d82a0 initial_suspend
0x6000013d82a0 final_suspend
0x6000013d82a0 await_ready
0x6000013d82a0 await_suspend (precursor = 0x6000008d81c0)
Result: 0

可见此时final_suspend先于await_suspend被调用,导致负责恢复父协程的precursor变量未被正确赋值,父协程无法恢复,最终结果错误。

疑问与需求

  • 这种行为是C++20协程的预期行为吗?
  • 该如何修复这个问题,让同步返回的协程也能正确触发父协程的恢复?
  • 额外问题:coroutine_handle无法直接检测底层promise是否还存在,导致无法在await_suspend内轻松判断当前协程是否已经进入final_suspend阶段。

相关代码

#include <coroutine>
#include <functional>
#include <iostream>
#include <list>

std::list<std::function<void (void)>> g_queue;

struct next_tick {
  bool await_ready() const noexcept {
    return false;
  }

  void await_resume() const noexcept {
  }

  void await_suspend(std::coroutine_handle<> coroutine) const noexcept {
    g_queue.push_back([coroutine] {
      coroutine.resume();
    });
  }
};

template <typename T>
struct task {
  struct promise_type {
    std::coroutine_handle<> precursor;
    T data;

    task get_return_object() noexcept {
      return {std::coroutine_handle<promise_type>::from_promise(*this)};
    }

    std::suspend_never initial_suspend() noexcept {
      std::cout << std::coroutine_handle<promise_type>::from_promise(*this).address() << " initial_suspend" << std::endl;
      return {};
    }

    void unhandled_exception() {
    }

    std::suspend_never final_suspend() noexcept {
      std::cout << std::coroutine_handle<promise_type>::from_promise(*this).address() << " final_suspend" << std::endl;

      if (precursor) {
        g_queue.push_back([this] {
          precursor.resume();
        });
      }

      return {};
    }

    void return_value(T value) noexcept {
      data = std::move(value);
    }
  };

  bool await_ready() const noexcept {
    std::cout << handle.address() << " await_ready" << std::endl;
    return false;
  }

  T await_resume() const noexcept {
    std::cout << handle.address() << " await_resume" << std::endl;
    return std::move(handle.promise().data);
  }

  void await_suspend(std::coroutine_handle<> coroutine) const noexcept {
    std::cout << handle.address() << " await_suspend (precursor = " << coroutine.address() << ")" << std::endl;

    if (handle.done())
      coroutine.resume();

    handle.promise().precursor = coroutine;
  }

  std::coroutine_handle<promise_type> handle;
};

task<int> bar() {
  // co_await next_tick();
  co_return 42;
}

task<int> foo() {
  co_return co_await bar();
}

int main() {
  auto coroutine = foo();

  while (!g_queue.empty()) {
    auto fn = g_queue.front();
    g_queue.pop_front();
    fn();
  }

  std::cout << "Result: " << coroutine.handle.promise().data << std::endl;
}

内容的提问来源于stack exchange,提问作者Maël Nison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:43:15