常见坑
每一页对着一个报错或一个现象:先给最小复现和实测输出,再到源码里找它从哪来,最后给出改法。机制在前面各章讲过的,这里只链过去。复现程序在 exp-crossbeam/pitfalls/(channel 相关的几条)、exp-crossbeam/worker-not-sync/,以及前面各章已有的实验目录;本机 M2 Max、rustc 1.99.1、依赖锁在本卷的版本,涉及本站的那一条另用 crossbeam-channel 0.5.15 复核。
channel
- 接收端都走了,有界 channel 里的消息还没析构:0.5.17 和 0.5.15 的
bounded(n)要等发送端也 drop 才析构缓冲消息;unbounded 和 std 立即析构。main的 #1121 改了这一点,升级后行为会变。 - select! 没有按书写顺序选:默认随机;要优先级用
select_biased!。 - bounded(0) 的 send 一直不返回:零容量是会合,没有接收方正在等就没有地方放;
try_send在接收方还没进recv时也是Full。 - send_timeout 的时间已经过了,消息还是发出去了:带超时的收发先尝试、后看表。
- tick 的间隔越来越长:
recv路径跟得上时不漂;try_recv和多分支select!每次都把醒来的延迟加进下一次。 - dropped
SelectedOperationwithout completing the operation:Select::select()预订了操作,必须完成。 - 在 tokio 任务里 recv,整个运行时卡住:crossbeam 的
recv阻塞线程,不让出任务。
epoch、deque、utils
- 一个线程一直 pin 着,内存只涨不降:全局纪元停住,所有垃圾都等着;这时
flush更糟。 - AtomicCell 不是 lock-free:大小或对齐对不上原生原子的类型走全局 seqlock。
- 把 Steal::Retry 当成 Empty,窃取者提前收工:不丢不重,只是慢。
Cell<Buffer<T>>cannot be shared between threads safely:Worker是Send不是Sync。- 子线程 panic 了,crossbeam::scope 没有 panic:它返回
Err(Vec);迁移到 std 的scope后行为变了。
flowchart TB chan["channel"] --> p1["1 有界 rx drop"] chan --> p3["3 bounded(0)"] chan --> p4["4 超时仍成功"] sel["select"] --> p2["2 随机"] sel --> p5["5 tick 漂移"] sel --> p6["6 SelectedOperation"] async["和 async 混用"] --> p7["7 阻塞 recv"] ep["epoch"] --> p8["8 长期 pin"] ut["utils"] --> p9["9 AtomicCell 走锁"] ut --> p12["12 scope 的 panic"] dq["deque"] --> p10["10 Retry 当 Empty"] dq --> p11["11 Worker 不是 Sync"]
按后果分:第 1、8 条是资源晚释放或内存增长,不报错;第 2、5、10 条是结果对、行为不对(顺序、节拍、并行度),最难发现;第 3、7 条是卡住;第 6、11 条是 panic 或编译错误,最容易发现;第 4、9、12 条是语义和直觉不一致。
删掉的候选
规划时还有一条「defer_destroy 之后还解引用旧 Shared、在 unprotected() 下并发访问」,打算用 Miri 复现。本机 nightly 没有装 Miri 组件,离线装不上,所以不单独成页。这条坑的原理和一个 loom 复现已经在 04 章:Shared 活不过 guard 是编译期保证的(Atomic、Owned、Shared),unprotected() 让 defer 立即执行(pin 与 Guard),把读者换成 unprotected() 后 loom 在第 21 个交错就报出旧对象被析构(Collector 与 LocalHandle)。
本站自己的代码没有直接用 crossbeam;这些坑在本站间接依赖里碰不碰得到,见 10 在本站中。
💬 关联讨论
发起讨论加载中...