rust - 如何从 Rust 中的不安全内存创建原子

标签 rust

我正在学习不安全的 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.

但是,您正在尝试将 指针 转换为 i64AtomicI64:

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/

相关文章:

arrays - 如何在 RUST 中逐字节比较 2 个不同的字符串文字

rust - 如何创建iter重复rust中的最后一个元素

postgresql - 如何从 Rust 中的 PostgreSQL 读取带有时区 (timestamptz) 值的时间戳?

reflection - 如何使用反射调用带有一些参数的未知 Rust 函数?

rust - Borrow in filter closure 的生命周期不够长

rust - 从parking_lot::RwLock返回映射的数据

rust - 如何从 OsStr 和 str 组件构建 URL?

rust - 为什么 impl trait 不能用于返回多个/条件类型?

rust - 从 Mutex 中同时借用引用和保护

rust - "does not live long enough"遍历链表时出错