the send_guard and deadlock_detection features cannot be used together
主线位置:不在主线上,是构建期的问题。两个 feature 一个改守卫的
Send性,一个按加锁线程记账,parking_lot 选择让它们互斥(GuardSend 与 send_guard);Cargo 的 feature 合并让「互斥」变成了「依赖图里任何两处不能分别打开」。
flowchart LR a["crate A:parking_lot features = send_guard"] --> u["Cargo 合并 feature:同一个 parking_lot v0.12.5"] b["crate B:parking_lot features = deadlock_detection"] --> u u --> ce["编译 parking_lot:compile_error!"] ce --> find["cargo tree -e features -i parking_lot"]
报错原文
E9 ① 的第三种组合(exp-parking_lot/guard-await,--features sg,dd,registry 路径已缩短):
Checking parking_lot v0.12.5
error: the `send_guard` and `deadlock_detection` features cannot be used together
--> parking_lot-0.12.5/src/lib.rs:35:1
|
35 | compile_error!("the `send_guard` and `deadlock_detection` features cannot be used together");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: could not compile `parking_lot` (lib) due to 1 previous error
错误出现在编译 parking_lot 的时候,指向的是 registry 里的源码,不是你的代码。你自己的 Cargo.toml 可能一个 feature 都没开。
源码出处
// If deadlock detection is enabled, we cannot allow lock guards to be sent to
// other threads.
#[cfg(all(feature = "send_guard", feature = "deadlock_detection"))]
compile_error!("the `send_guard` and `deadlock_detection` features cannot be used together");
死锁检测把「本线程持有哪些锁」记在加锁线程的 ThreadData 里,解锁时在当前线程的记录里删(死锁检测)。守卫换了线程,记录就对不上,上游因此禁止两者同开。send_guard 引入于 0.11.0(#240,提交说明「But only if deadlock detection is not enabled.」)。
Cargo 对同一个包取所有依赖打开的 feature 的并集。所以:
- A 依赖开了
send_guard,B 依赖(或者你为了调试)开了deadlock_detection,两者在 parking_lot 里相遇。 - 反过来,只有一方开了
send_guard,整个程序里所有 parking_lot 守卫都变成Send,包括你自己代码里的,编译器不会提醒。
怎么找出是谁
cargo tree -e features -i parking_lot
guard-await 开 sg 时的输出(节选,完整输出在 GuardSend 与 send_guard),最后一个分支就是打开 send_guard 的人:
parking_lot v0.12.5
├── parking_lot feature "arc_lock"
│ └── guard-await v0.1.0 (exp-parking_lot/guard-await)
├── parking_lot feature "default"
│ └── guard-await v0.1.0 (exp-parking_lot/guard-await) (*)
└── parking_lot feature "send_guard"
└── guard-await feature "sg" (command-line)
本站两个工作区的 parking_lot 都没有这两个 feature,见 10 在本站中。
怎么改
- 调试时临时打开
deadlock_detection撞上了这个错误:说明依赖图里有人开了send_guard,调试期间只能在不依赖它的二进制或测试里打开死锁检测。 - 库作者不要在库里打开
send_guard:它会改变所有下游的守卫类型,还会让下游无法开死锁检测。库里需要可跨线程的守卫,用ArcMutexGuard(arc_lockfeature)或换一种锁。 - 库作者也可以学 tokio 把外溢挡住:tokio 内部把 parking_lot 的类型再包一层,每个包装都带
PhantomData<std::sync::...>,注释写明是为了「ensure that parking_lot's send_guard feature does not leak through and affect when Tokio types are Send」(tokio 1.52.3src/loom/std/parking_lot.rs第 12–15 行,tokio PR #4359)。这样别人开不开send_guard,tokio 自己类型的Send性都和用 std 锁时一样。
小结
- 报错来自
src/lib.rs:35的compile_error!,出现在编译 parking_lot 时。 - 原因通常是依赖图里两处分别打开了两个 feature,Cargo 合并后撞在一起。
cargo tree -e features -i parking_lot的分支直接写出是谁打开了哪个 feature。- 库不要打开
send_guard;需要挡住外溢可以学 tokio 用PhantomData包一层。
💬 关联讨论
发起讨论加载中...