我编写的代码有点像这样:
#![no_std]
static mut DATA: usize = 0;
#[no_mangle]
pub unsafe fn update() {
DATA = 1;
}
#[no_mangle]
pub unsafe fn wait_for_data() {
while DATA == 0 {}
DATA = 1;
}
在我的例子中,
update
函数由硬件中断调用,并且wait_for_data
在主程序中运行。因此,我们可以假设 DATA
在 while
循环期间会发生变化。我假设 static mut
会告诉编译器该地址可以在多个并发执行线程之间共享。但是,编译器会通过在第一次迭代时跳转到无限循环 if DATA == 0
来优化此代码。
现在我的问题是:
DATA
的并发访问?问题是,你告诉编译器你知道你在做什么(
wait_for_data
是unsafe
)。但是使用 PartialEq
(通过 ==
)意味着 wait_for_data
需要共享对 DATA
的引用(签名是 fn eq(&self, other: &Rhs) -> bool;
),所以你保证,不存在对 DATA
的 mutalbe 引用,因为那将是UB 每:
打破指针别名规则。 Box、&mut T 和 &T 遵循 LLVM 的作用域 noalias 模型,除非 &T 包含 UnsafeCell。参考文献和盒子在使用时不得悬挂。确切的活跃持续时间没有指定,但存在一些界限:
- 作为参考,活跃持续时间的上限由借用检查器分配的语法生命周期决定;它的寿命不能超过该寿命。
- 每次将引用或框传递给函数或从函数返回时,它都被视为活动。
- 当引用(但不是 Box!)传递给函数时,它至少与该函数调用一样长,除非 &T 包含 UnsafeCell。
当这些类型的值在复合类型的(嵌套)字段中传递时,所有这些也适用,但不在指针间接后面传递。
因此编译器可以安全地假设
DATA
不会改变,并优化循环。