源码地图
主线位置:三条主线经过的 crate 和文件。主线 1(一条消息)全在 crossbeam-channel 里,主线 2(一个任务)在 crossbeam-deque,主线 3(一块内存的回收)在 crossbeam-epoch;三条线都踩在 crossbeam-utils 上。
flowchart BT utils["crossbeam-utils 0.8.23"] epoch["crossbeam-epoch 0.9.21"] --> utils deque["crossbeam-deque 0.8.8"] --> epoch deque --> utils chan["crossbeam-channel 0.5.17"] --> utils queue["crossbeam-queue 0.3.14"] --> utils skip["crossbeam-skiplist 0.1.3(不在发布分支)"] --> epoch skip --> utils facade["crossbeam 0.8.5(门面)"] --> chan facade --> deque facade --> epoch facade --> queue facade --> utils
crate 与依赖
依赖只有一个方向:utils 在最底下,不依赖任何 crossbeam crate;epoch 依赖 utils;deque 和 skiplist 依赖 epoch 和 utils;channel 和 queue 只依赖 utils。门面 crossbeam 依赖除 skiplist 外的全部。行数是 src/ 下 .rs 的总行数,含文档注释和文件内的单元测试,不含 tests/、benches/:
| crate | 版本 | MSRV | 默认 feature | src/ 行数 | 本卷 |
|---|---|---|---|---|---|
crossbeam-utils | 0.8.23 | 1.60 | std | 4168 | 03 |
crossbeam-epoch | 0.9.21 | 1.61 | std(含 alloc) | 4945 | 04 |
crossbeam-deque | 0.8.8 | 1.61 | std | 2367 | 05 |
crossbeam-channel | 0.5.17 | 1.60 | std | 7844 | 06 |
crossbeam-queue | 0.3.14 | 1.60 | std(含 alloc) | 1392 | 07 |
crossbeam-skiplist(tag crossbeam-skiplist-0.1.3) | 0.1.3 | 1.61 | std(含 alloc) | 3792 | 07 |
crossbeam(门面) | 0.8.5 | 1.61 | std(含 alloc) | 84 | 本页 |
工作区根 Cargo.toml 的 members 里,skiplist 那一行被注释掉了:
members = [
".",
"crossbeam-channel",
"crossbeam-channel/benchmarks",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
# "crossbeam-skiplist", # Not published from this branch.
"crossbeam-utils",
]
这就是为什么 skiplist 用的是另一个 tag:发布分支上的 skiplist 目录比 0.1.3 还旧(Cargo.toml 写 version = "0.0.0"),见 怎么读这一卷。
门面 crate
src/lib.rs 是 #![no_std],正文只有重导出:
pub use crossbeam_utils::atomic;
pub mod utils {
pub use crossbeam_utils::Backoff;
pub use crossbeam_utils::CachePadded;
}
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use {crossbeam_epoch as epoch, crossbeam_queue as queue};
#[cfg(feature = "std")]
#[doc(inline)]
pub use {
crossbeam_channel as channel, crossbeam_channel::select, crossbeam_deque as deque,
crossbeam_utils::sync,
};
#[cfg(feature = "std")]
#[cfg(not(crossbeam_loom))]
pub use crossbeam_utils::thread::{self, scope};
no_std 下只剩 atomic 和 utils;开 alloc 多出 epoch、queue;std 才有 channel、select!、deque、sync 和 scope。crossbeam::scope 在 cfg(crossbeam_loom) 下不存在。
每个文件管什么
crossbeam-utils
| 文件 | 行数 | 内容 |
|---|---|---|
lib.rs | 110 | 两份 mod primitive(loom 与否),模块声明 |
cache_padded.rs | 223 | CachePadded<T> |
backoff.rs | 287 | Backoff |
atomic/atomic_cell.rs | 1214 | AtomicCell<T>、atomic! 宏、67 把全局锁 |
atomic/seq_lock.rs、seq_lock_wide.rs | 112、155 | 锁路径用的 seqlock;32 位平台用 wide 版 |
atomic/consume.rs | 111 | AtomicConsume::load_consume |
sync/parker.rs | 415 | Parker、Unparker |
sync/sharded_lock.rs | 638 | ShardedLock 与线程编号表 |
sync/wait_group.rs | 155 | WaitGroup |
sync/once_lock.rs | 88 | 照 std 抄的 OnceLock(MSRV 低于 1.70) |
thread.rs | 611 | 作用域线程 |
crossbeam-epoch
| 文件 | 行数 | 内容 |
|---|---|---|
atomic.rs | 1713 | Atomic、Owned、Shared、Pointable、标签位 |
internal.rs | 618 | Global、Local、Bag、pin / unpin、collect、try_advance |
guard.rs | 523 | Guard、defer*、flush、repin、unprotected |
collector.rs | 465 | Collector、LocalHandle(一半是测试) |
sync/list.rs、sync/queue.rs | 488、469 | 参与者链表(Michael 2002)、袋子队列(Michael-Scott) |
deferred.rs | 149 | Deferred:内联 3 个 usize 的闭包 |
epoch.rs | 149 | Epoch、AtomicEpoch |
default.rs | 93 | 默认收集器、epoch::pin() |
crossbeam-deque:deque.rs 一个文件 2261 行,Worker、Stealer、Injector、Steal;lib.rs 只有文档和重导出。
crossbeam-channel
| 文件 | 行数 | 内容 |
|---|---|---|
channel.rs | 1534 | bounded / unbounded / after / at / tick / never,Sender、Receiver,迭代器 |
select.rs | 1299 | Token、Operation、Selected、SelectHandle、run_select、Select |
select_macro.rs | 1153 | select! / select_biased! 的宏展开规则 |
flavors/list.rs、array.rs、zero.rs | 788、655、486 | 无界、有界、零容量三种可收发的 flavor |
flavors/at.rs、tick.rs、never.rs | 197、167、110 | 只能接收的三种定时 flavor |
err.rs | 378 | 错误类型 |
waker.rs、context.rs、counter.rs、utils.rs | 287、178、144、73 | 阻塞与唤醒、线程本地上下文、收发端计数、忽略 poison 的 Mutex |
crossbeam-queue:seg_queue.rs 713 行,array_queue.rs 645 行。
crossbeam-skiplist(0.1.3):base.rs 2123 行(跳表本体),map.rs 783 行、set.rs 629 行(带默认收集器的包装),lib.rs 257 行。
feature
| feature | 在哪些 crate | 打开什么 |
|---|---|---|
std(默认) | 全部 | 依赖 std 的 API。channel 和 deque 的 Cargo.toml 注明「Disabling std feature is not supported yet」,关掉后它们几乎什么都不剩 |
alloc(std 隐含) | epoch、queue、skiplist、门面 | 需要分配但不需要 std 的 API:epoch 整体、ArrayQueue / SegQueue |
nightly | utils、epoch、queue、门面 | 三个子 crate 的 Cargo.toml 都写着「These features are no longer used」,留着只为兼容,下个大版本删除;门面的 nightly 只是转发 |
loom | epoch(显式)、utils(可选依赖隐含) | 引入 loom 0.7 依赖;还要配合 --cfg crossbeam_loom 才会生效 |
cfg
除 feature 外,源码里还有五个 cfg 改变行为。它们不是 feature,由 RUSTFLAGS、构建脚本或编译器给出:
| cfg | 谁打开 | 改了什么 |
|---|---|---|
crossbeam_loom | 手动 RUSTFLAGS="--cfg crossbeam_loom"(加 loom feature) | utils、epoch 的 mod primitive 换成 loom 原语;AtomicCell、ShardedLock、thread 不编译;门面不导出 scope(怎么验证并发代码) |
crossbeam_sanitize | 手动,CI 的 sanitizer 和 loom 任务传入 | epoch 的袋子从 64 个对象降到 4 个、collect 不限步数;几个计时敏感的测试跳过 |
crossbeam_sanitize_thread | utils、epoch、deque 的 build.rs:CARGO_CFG_SANITIZE 含 thread,或目标是 x86_64-unknown-linux-gnutsan | 「Relaxed + fence」改写成 TSan 能理解的 Acquire / Release 访问;load_consume 退回 Acquire |
crossbeam_no_atomic | utils 的 build.rs:目标在 no_atomic.rs 列出的 8 个之中(armv4t-none-eabi、msp430-none-elf、thumbv4t-none-eabi 等);也可手动设 | 假定目标没有任何原子操作:utils 的 mod primitive 不再引入原子类型,AtomicConsume 没有实现。build.rs 注释说它是「公开但不稳定」的 API |
miri | Miri 自动设 | epoch 袋子降到 4、x86 的 CAS 代替 fence 关掉、load_consume 退回 Acquire |
no_atomic.rs 是 ci/no_atomic.sh 生成的:用 rustc --print all-target-specs-json 找出 max-atomic-width 为 0、或者最小原子宽度不是 8 的目标。CI 的 codegen 任务每次重新生成一遍,git diff --exit-code 确认文件没过时。
本卷只在 aarch64 macOS 上用默认 feature 编译和运行,以上 cfg 都没有打开。
MSRV
README 写的是 1.61;各 crate 的 rust-version 是 1.60(utils、channel、queue)或 1.61(epoch、deque、skiplist、门面)。0.8.23 / 0.5.17 这一轮把政策从「支持半年内的 Rust」改成「支持一年内」(#1284),理由写的是和 rayon 的 MSRV 政策对齐。CI 的 test 矩阵最低测到 1.65(Linux)和 1.71(Windows),features 任务用 cargo hack --rust-version 按各 crate 声明的 MSRV 编译(不跑测试)。
低 MSRV 解释了 utils 和 epoch 为什么各自带一份 OnceLock(std 的要 1.70 才稳定)。另有几处注释比 MSRV 还旧:x86 上 pin 那段说「stable 上用不了内联汇编」(asm! 1.59 已稳定),AtomicCell 那段说「AtomicU8 在 stable 上不可用」。
小结
- 五个发布 crate 加门面:utils 在底层,epoch 依赖 utils,deque 依赖 epoch,channel、queue 只依赖 utils;门面只做重导出,
no_std/alloc/std三档逐级放开。 - skiplist 不在发布分支的工作区成员里,本卷用 tag
crossbeam-skiplist-0.1.3,src/共 3792 行。 - feature 只有
std、alloc、nightly(已无作用)、loom;真正改行为的是五个 cfg:crossbeam_loom、crossbeam_sanitize、crossbeam_sanitize_thread、crossbeam_no_atomic、miri。 - MSRV 1.60 / 1.61,CI 测到 1.65 / 1.71。