如何从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::t

我正在学习不安全的锈迹,并试图创建一个原子,该原子由指向某个不安全内存(例如,来自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));
    }
}
我会做好的。您只能从可变指针构造它,因为它必须拥有指向的数据

如果您有一个共享/共享的原始指针(const指针),它在设计上就不能是原子的。如果要共享指针,它必须是
Arc
后面的
AtomicPtr

提醒一下,可变引用/指针等于unique,常量引用/指针等于shared。如果您违反此规则,则您的程序是未定义的行为。

说明:

此类型与基础整数类型i64具有相同的内存表示形式

但是,您正在尝试将指向
i64
的指针转换为
AtomicI64

不安全{
设a=std::mem::transmute:(ptr);
//这是一个指针^^^^^^^^
//^^^^^^^^^^^不是指针
}
相反,您需要将
*muti64
转换为指向
AtomicI64
的指针或引用

可以这样实现(安全和不安全变体):

//如果我们有一个mut引用,它必须对
//引用的数据,因此我们可以安全地将其转换为不可变的引用
//到原子64
fn使原子化和原子化{
不安全{
&*(src as*mut i64 as*const AtomicI64)
}
}
//如果我们有一个mut指针,我们不能保证所有权或生存期,并且
//因此,强制转换为对AtomicI64的不可变引用是不安全的
不安全的fn使原子化{
//声明基础缓冲区
让mut v=vec![1i64,2i64];
{
//安全获取原子能
设atomic=make_atomic_i64(&mut v[0]);
//尝试访问原子
println!(“{}”,atomic.swap(10,Ordering::Relaxed));/=1
}
不安全{
//不安全地获取原子
设atomic=make_ptr_atomic_i64(&mut v[0]为*mut i64);
//尝试访问原子
println!(“{}”,atomic.swap(100,Ordering::Relaxed));/=10
}
//打印变量的最终状态
println!(“{}”,v[0]);/=100
}

但是如果我这样做了,让x=AtomicPtr::new(ptr)*(x.load(Ordering::Relaxed))那么原子访问似乎是指向指针本身,而不是指向
i64
内容?取消对内容的引用不是原子性的。我的意思是,使用
*
*mut i64
中获得的
*
进行的第二次取消引用不是原子性的。用例是指针保持稳定,但我对
i64
值进行
compare\u和\u swap
。@V.B.我可能是错的,但我认为取消引用指针不会有任何问题,因为它不是共享的。请注意,它不是克隆。在不安全的代码中,这取决于你是否违反这条规则。我处于不安全的境地,通过不同进程(甚至线程)的共享内存进行无锁同步。所以可以同时访问指针的
i64
内容。@V.B.这是另一个问题。我甚至不确定这在锈病中是否可行…谢谢!您在我的Update 2编辑后30分钟回答了我的问题(我想您已经看到了),在那里我用同样的布局推理做了基本相同的事情,但即使没有转换并使用
作为*const i64作为*const AtomicI64
。那么你确认这不是UB?或者《终生蜕变》比《密码》中的《施放》更好/更正确?@V.B.在我回答之前我没有看到你的更新,但是是的,你似乎得出了同样的结论。是的,据我所知,它不应该是:
AtomicI64
始终具有与
i64
相同的内存表示形式,指针和引用也是如此()。只要数据是以原子方式访问的,我看不出有任何理由认为它应该是未定义的行为。谢谢!有没有一种方法可以将生存期附加到
as
指针强制转换?@V.B.您不能使用
as
强制转换,但可以在取消引用时执行:
让x:&'a AtomicI64=&*x我错过了@trentcl删除的一些评论。为什么通过
as
进行指针转换比transmute更受欢迎?
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]);
    }
}