Skip to content

docs(readme): spawn + co_await example; document .await() deadlock boundary - #90

Merged
mivinci merged 1 commit into
mainfrom
codebuddy/readme-spawn-coawait
Aug 26, 2026
Merged

mivinci merged 1 commit into
mainfrom
codebuddy/readme-spawn-coawait

Conversation

@mivinci

@mivinci mivinci commented Aug 26, 2026

Copy link
Copy Markdown
Owner

背景

README 顶部示例原用 xpp::fiber + .await()。换成 spawn 时发现:spawn 是
poll 驱动的执行体,它的惯用等待是 co_await(或 C++11 的 .then()),而
.await() 是 fiber 的等待方式。

改动

  • README 示例:fiber + .await() → spawn + co_await(channel 生产/消费,sum=210)
  • spawn.h 文档:补充 .await() 在 spawn fn 里的跨任务依赖循环死锁边界
    ——嵌套 park 使外层 X_RUN_ONCE 无法返回检查 woken,consumer 等生产、producer
    等消费即死锁;推荐 .then()/co_await(waker 驱动、无嵌套栈)
  • todos/fiber-driven-spawn-await.md:记录根治方向——spawn 的 fn 跑在 fiber 里,
    .await() 自动走 xFiberYield(不嵌套 loop),让 .await() 在 spawn 里普遍可用

关键发现

PromiseContext::park() 已有 fiber 分支(xFiberYield),但 spawn 的 fn 跑在普通
栈上,.await() 走同步阻塞 + 嵌套 X_RUN_ONCE。两个 spawn 任务互相 await 时形成
嵌套 park 环 → 死锁。timer/I/O 场景安全(回调不嵌套 park);依赖循环必死锁。

验证

co_await 版示例临时测试通过(sum: 210,无死锁),临时文件已删除。

…undary

The README's top example used xpp::fiber + .await(). Switch it to
xpp::spawn + co_await — the idiomatic pairing for the poll-driven spawn
executor, while .await() is the fiber pairing.

Discovered while validating the example that .await() inside a spawned
fn deadlocks on cross-task dependency cycles (nested park blocks the
outer loop from re-checking its woken flag). Document the boundary in
spawn.h and file todos/fiber-driven-spawn-await.md for a fiber-driven
spawn that would make .await() universally safe.
@mivinci
mivinci merged commit 26198e2 into main Aug 26, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant