我正在学习不安全的 Rust 并尝试创建一个由指向某些不安全内存(例如来自 C 或内存映射文件的缓冲区)的指针支持的原子。
我试过这个:
use std::sync::atomic::{AtomicI64, Ordering};
fn main() -> () {
let mut v = vec![1i64, 2i64];
let ptr = &mut v[0] as *mut i64;
unsafe {
let a = std::mem::transmute::<*mut i64, AtomicI64>(ptr);
println!("{}", a.load(Ordering::Relaxed));
}
}
但它打印指针的地址(例如 2119547391296
)而不是 1
。
创建位于某个外部缓冲区中的原子的正确方法是什么?
我想要相同的功能,例如C# Interlocked.CompareExchange(ref *(long*)ptr, ...)
,所以也许还有其他方法可以在 Rust 中获取无锁同步原语?
更新:
看起来我需要 std::intrinsics::{*}
,但它们在稳定的 Rust 中不可用。
更新 2:
这会编译并打印 1 2 2
(即 v[0]
通过指针转换创建的 AtomicI64
按预期更新,然后取消引用AtomicI64
通过 & *ptr
)。但这是正确的吗?
use std::sync::atomic::{AtomicI64, Ordering};
fn main() -> () {
let v = vec![1i64, 2i64];
let ptr = &v[0] as *const i64 as *const AtomicI64;
unsafe {
let a = & *ptr;
println!("{}", a.load(Ordering::SeqCst));
a.fetch_add(1i64, Ordering::SeqCst);
println!("{}", a.load(Ordering::SeqCst));
println!("{}", v[0]);
}
}
最佳答案
documentation for AtomicI64
是这样说的:
This type has the same in-memory representation as the underlying integer type, i64.
但是,您正在尝试将 指针 转换为 i64
到 AtomicI64
:
unsafe {
let a = std::mem::transmute::<*mut i64, AtomicI64>(ptr);
// is a pointer ^^^^^^^^
// ^^^^^^^^^ is not a pointer
}
相反,您需要将 *mut i64
转换为指针或对 AtomicI64
的引用。
这可以像这样实现(安全和不安全的变体):
// if we have a mut reference, it must have unqiue ownership over the
// referenced data, so we can safely cast that into an immutable reference
// to AtomicI64
fn make_atomic_i64<'a>(src: &'a mut i64) -> &'a AtomicI64 {
unsafe {
&*(src as *mut i64 as *const AtomicI64)
}
}
// if we have a mut pointer, we have no guarantee of ownership or lifetime, and
// therefore it's unsafe to cast into an immutable reference to AtomicI64
unsafe fn make_ptr_atomic_i64<'a>(src: *mut i64) -> &'a AtomicI64 {
&*(src as *const AtomicI64)
}
Example :
use std::sync::atomic::{AtomicI64, Ordering};
fn main() -> () {
// declare underlying buffer
let mut v = vec![1i64, 2i64];
{
// get atomic safely
let atomic = make_atomic_i64(&mut v[0]);
// try to access atomic
println!("{}", atomic.swap(10, Ordering::Relaxed)); // = 1
}
unsafe {
// get atomic unsafely
let atomic = make_ptr_atomic_i64(&mut v[0] as *mut i64);
// try to access atomic
println!("{}", atomic.swap(100, Ordering::Relaxed)); // = 10
}
// print final state of variable
println!("{}", v[0]); // = 100
}
关于rust - 如何从 Rust 中的不安全内存创建原子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57009043/