Jef*_*ges 5 multithreading raii rust
我发现mem::drop没有必要在它被调用的地方附近运行,这可能导致在昂贵的计算过程中保持Mutex或RwLock守卫.如何控制何时drop被调用?
作为一个简单的例子,我通过使用unsafe { ::std::intrinsics::drop_in_place(&mut s); }而不是简单地对密码材料工作的归零进行了以下测试::std::mem::drop(s).
#[derive(Debug, Default)]
pub struct Secret<T>(pub T);
impl<T> Drop for Secret<T> {
fn drop(&mut self) {
unsafe { ::std::intrinsics::volatile_set_memory::<Secret<T>>(self, 0, 1); }
}
}
#[derive(Debug, Default)]
pub struct AnotherSecret(pub [u8; 32]);
impl Drop for AnotherSecret {
fn drop(&mut self) {
unsafe { ::std::ptr::write_volatile::<$t>(self, AnotherSecret([0u8; 32])); }
assert_eq!(self.0,[0u8; 32]);
}
}
#[cfg(test)]
mod tests {
macro_rules! zeroing_drop_test {
($n:path) => {
let p : *const $n;
{
let mut s = $n([3u8; 32]); p = &s;
unsafe { ::std::intrinsics::drop_in_place(&mut s); }
}
unsafe { assert_eq!((*p).0,[0u8; 32]); }
}
}
#[test]
fn zeroing_drops() {
zeroing_drop_test!(super::Secret<[u8; 32]>);
zeroing_drop_test!(super::AnotherSecret);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用::std::mem::drop(s)或甚至使用此测试失败
#[inline(never)]
pub fn drop_now<T>(_x: T) { }
Run Code Online (Sandbox Code Playgroud)
显然很好drop_in_place用于缓冲区变为零的测试,但是我担心调用drop_in_place一个Mutex或一个RwLock后卫可能会导致免费使用.
可以用这种方法处理这两个警卫:
#[inline(never)]
pub fn drop_now<T>(t: mut T) {
unsafe { ::std::intrinsics::drop_in_place(&mut t); }
unsafe { ::std::intrinsics::volatile_set_memory::<Secret<T>>(&t, 0, 1); }
}
Run Code Online (Sandbox Code Playgroud)
是的:副作用。
一般来说,优化器,特别是 LLVM,在 as-if 规则下运行:您构建一个具有特定可观察行为的程序,并且优化器可以自由地生成它想要的任何二进制文件,只要它具有完全相同的可观察行为行为。
请注意,举证责任在于编译器。也就是说,当调用不透明函数(例如在另一个库中定义)时,编译器必须假设它可能有副作用。此外,副作用不能重新排序,因为这可能会改变可观察的行为。
例如,在 的情况下Mutex,获取和释放Mutex通常对于编译器来说是不透明的(它需要操作系统调用),因此它被视为副作用。我希望编译器不要摆弄这些。
另一方面,你的Secret情况很棘手:大多数时候,删除秘密并没有副作用(将要释放的内存清零是死写,需要优化),这就是为什么你需要不遗余力地确保它发生......通过让编译器相信使用写入会产生副作用volatile。
| 归档时间: |
|
| 查看次数: |
105 次 |
| 最近记录: |