Rust 如何在cortex-m0上有多个可变引用?

Rust 如何在cortex-m0上有多个可变引用?,rust,atomic,Rust,Atomic,我正在为没有原子的cortex-m0处理器编写代码。我希望能够有一个引用仅用于读取值,另一个引用仅用于写入值。我想实现只强制写入和读取的设计约束 我的目标是使存储的变量的大小能够用单个CPU指令写入。这通常是通过允许读-修改-写的原子来完成的,但我不会进行读-修改-写,只读或只写 这种情况的用例是中断处理程序写入一个由主代码读取的值,或者主代码写入一个由中断处理程序读取的(不同的)值 我在想象我会用这样的物体: let mut thing = get_new_thing(5 as u8); le

我正在为没有原子的cortex-m0处理器编写代码。我希望能够有一个引用仅用于读取值,另一个引用仅用于写入值。我想实现只强制写入和读取的设计约束

我的目标是使存储的变量的大小能够用单个CPU指令写入。这通常是通过允许读-修改-写的原子来完成的,但我不会进行读-修改-写,只读或只写

这种情况的用例是中断处理程序写入一个由主代码读取的值,或者主代码写入一个由中断处理程序读取的(不同的)值

我在想象我会用这样的物体:

let mut thing = get_new_thing(5 as u8);
let mut reader = thing.get_reader();
let mut writer = thing.get_writer();

reader.read();
writer.write(12 as u8);

///not allowed
reader.write(5 as u8);
writer.read();

按照杰伊·皮的建议,你可以这样做


我不知道如何在safe-Rust中实现,因为您显然希望同时拥有读写器(
RefCell
将需要一些运行时开销)。请注意,没有同步,因此多线程需要一个
互斥体

,我提出了一个解决方案,它实现了

这应限于可在单个CPU周期内写入的数据类型(
u8
u16
u32
usize
i8
i16
,等等)。这段代码还没有做到这一点

Nothing
类型(字段
r
w
\u b
)防止从单个
IntSharedData
收集多个读卡器/写卡器,并强制执行读卡器和写卡器的生存期

不安全代码在这里起作用,因为只有一个实例在一次使用一个时钟周期写入值。读者对他们阅读的价值总是有一致的看法

#[derive(Debug)]
pub struct IntSharedData<T> {
    data: T,
    r: Nothing,
    w: Nothing,
}

pub struct UsableSharedReader<'a, T, OWNER> {
    d: *const T,
    _b: &'a Nothing,
    _owner: OWNER,
}

pub struct UsableSharedWriter<'a, T, OWNER> {
    d: *mut T,
    _b: &'a Nothing,
    _owner: OWNER,
}

#[derive(Debug)]
pub struct Nothing;
pub struct Interrupt;
pub struct Thread;

pub fn new_data<T>(value: T) -> IntSharedData<T> {
    IntSharedData::<T> {
        data: value,
        r: Nothing,
        w: Nothing,
    }
}

impl<'a, T, OWNER> UsableSharedWriter<'a, T, OWNER>
where
    T: Copy,
{
    pub fn write(&mut self, val: T) {
        unsafe {
            *self.d = val;
        }
    }
}

impl<'a, T, OWNER> UsableSharedReader<'a, T, OWNER>
where
    T: Copy,
{
    pub fn read(&self) -> T {
        unsafe { *self.d }
    }
}

impl<T> IntSharedData<T>
where
    T: Copy,
{
    pub fn get_rw_to_interrupt(
        &mut self,
    ) -> (
        UsableSharedReader<T, Interrupt>,
        UsableSharedWriter<T, Thread>,
    ) {
        let r = UsableSharedReader::<T, Interrupt> {
            d: &mut self.data as *const T,
            _owner: Interrupt,
            _b: &mut self.r,
        };
        let wd = &mut self.data as *mut T;
        let w = UsableSharedWriter::<T, Thread> {
            d: wd,
            _owner: Thread,
            _b: &mut self.w,
        };
        return (r, w);
    }

    pub fn get_rw_from_interrupt(
        &mut self,
    ) -> (
        UsableSharedReader<T, Thread>,
        UsableSharedWriter<T, Interrupt>,
    ) {
        let r = UsableSharedReader::<T, Thread> {
            d: &mut self.data,
            _owner: Thread,
            _b: &mut self.r,
        };
        let w = UsableSharedWriter::<T, Interrupt> {
            d: &mut self.data,
            _owner: Interrupt,
            _b: &mut self.w,
        };
        return (r, w);
    }
}

fn main() {
    let mut element = new_data(5 as u8);
    let (r, mut w) = element.get_rw_from_interrupt();
    //let (mut a,mut b) = element.get_rw_from_interrupt();

    let v1 = r.read();

    w.write(5);
    let v2 = r.read();

    println!("v1: {}, v2: {}, t: {:?}", v1, v2, element);
}
#[派生(调试)]
pub结构IntSharedData{
数据:T,
r:没什么,
w:没什么,
}
pub结构UsableSharedData IntSharedData{
IntSharedData::{
数据:价值,
r:没什么,
w:没什么,
}
}
恳求
哪里
T:收到,
{
发布fn写入(&mut self,val:T){
不安全{
*self.d=val;
}
}
}
恳求
哪里
T:收到,
{
发布fn读取(&self)->T{
不安全的{*self.d}
}
}
impl IntSharedData
哪里
T:收到,
{
pub fn get_rw_to_中断(
&莫特·赛尔夫,
) -> (
可使用共享恐惧者,
UsableSharedWriter,
) {
设r=UsableSharedReader::{
d:&将self.data变为*const T,
_所有者:打断,
_b:&mut self.r,
};
设wd=&mut self.data为*mut T;
设w=UsableSharedWriter::{
d:wd,
_所有者:线程,
_b:&mut self.w,
};
返回(r,w);
}
pub fn从中断中获取(
&莫特·赛尔夫,
) -> (
可使用共享恐惧者,
UsableSharedWriter,
) {
设r=UsableSharedReader::{
d:&mut self.data,
_所有者:线程,
_b:&mut self.r,
};
设w=UsableSharedWriter::{
d:&mut self.data,
_所有者:打断,
_b:&mut self.w,
};
返回(r,w);
}
}
fn main(){
设mut元素=新的_数据(5为u8);
let(r,mut w)=元素。从_中断()获取_rw_;
//let(mut a,mut b)=元素。从_中断()获取_rw_;
设v1=r.read();
w、 写(5);
设v2=r.read();
println!(“v1:{},v2:{},t:{:?}”,v1,v2,元素);
}

如果我理解正确,您在M0单线程CPU上使用的是生锈的裸机,希望处理平台中断

您的场景似乎非常特殊,原因有两个:

  • CPU没有任何原子支持,因为考虑到只有一个内核,它们没有任何意义
  • 你仍然有某种形式的“线程”,即使你在一个CPU上,考虑到你的代码可能在任何地方被中断,以切换到处理中断钩子。中断处理程序应被视为单独的“线程”,您不能向它们发送非发送数据。事实上,在裸机环境中
这里解决方案的关键点是,即使CPU上没有跨核原子,Rust core中也应该有原子,至少支持
加载
存储
,跨中断提供安全的可变内存位置,这是一个非常难以正确解决的问题,因为如果编译器在单个内核上运行,并且可能不会被中断,则编译器能够广泛地优化内容。(因此,我不完全相信目前提出的其他解决方案是正确的,请参阅。)

使用这些原子(且无不安全因素),您的问题的解决方案如下所示:

注意:为了遵循常见的Rust语义,您可能希望在读写器上使用
.get()
.set()
作为方法(匹配项)。它还有一个额外的优点,就是它消除了每次是否要覆盖一个值的模糊性,而在阅读问题时,我最初并不完全确定这一点。我在实现中使用这些名称

#![无标准]
#![无主]
使用紧急停止作为uu;
使用cortex_m_rt::{entry,exception};
mod读写器{
//!用于限制原子读取或写入的简单包装器
使用core::sync::atomic::{AtomicUsize,Ordering};
发布结构AtomicUsizeWrapper{
内部:原子化,
}
植入原子音乐包装器{
酒吧常数fn新(val:usize)->Self{
自我{
内部:原子化::新建(val),
}
}
发布fn获取(&self)->使用{
self.internal.load(排序::SeqCst)
}
发布fn集(&self,val:usize)
#[derive(Debug)]
pub struct IntSharedData<T> {
    data: T,
    r: Nothing,
    w: Nothing,
}

pub struct UsableSharedReader<'a, T, OWNER> {
    d: *const T,
    _b: &'a Nothing,
    _owner: OWNER,
}

pub struct UsableSharedWriter<'a, T, OWNER> {
    d: *mut T,
    _b: &'a Nothing,
    _owner: OWNER,
}

#[derive(Debug)]
pub struct Nothing;
pub struct Interrupt;
pub struct Thread;

pub fn new_data<T>(value: T) -> IntSharedData<T> {
    IntSharedData::<T> {
        data: value,
        r: Nothing,
        w: Nothing,
    }
}

impl<'a, T, OWNER> UsableSharedWriter<'a, T, OWNER>
where
    T: Copy,
{
    pub fn write(&mut self, val: T) {
        unsafe {
            *self.d = val;
        }
    }
}

impl<'a, T, OWNER> UsableSharedReader<'a, T, OWNER>
where
    T: Copy,
{
    pub fn read(&self) -> T {
        unsafe { *self.d }
    }
}

impl<T> IntSharedData<T>
where
    T: Copy,
{
    pub fn get_rw_to_interrupt(
        &mut self,
    ) -> (
        UsableSharedReader<T, Interrupt>,
        UsableSharedWriter<T, Thread>,
    ) {
        let r = UsableSharedReader::<T, Interrupt> {
            d: &mut self.data as *const T,
            _owner: Interrupt,
            _b: &mut self.r,
        };
        let wd = &mut self.data as *mut T;
        let w = UsableSharedWriter::<T, Thread> {
            d: wd,
            _owner: Thread,
            _b: &mut self.w,
        };
        return (r, w);
    }

    pub fn get_rw_from_interrupt(
        &mut self,
    ) -> (
        UsableSharedReader<T, Thread>,
        UsableSharedWriter<T, Interrupt>,
    ) {
        let r = UsableSharedReader::<T, Thread> {
            d: &mut self.data,
            _owner: Thread,
            _b: &mut self.r,
        };
        let w = UsableSharedWriter::<T, Interrupt> {
            d: &mut self.data,
            _owner: Interrupt,
            _b: &mut self.w,
        };
        return (r, w);
    }
}

fn main() {
    let mut element = new_data(5 as u8);
    let (r, mut w) = element.get_rw_from_interrupt();
    //let (mut a,mut b) = element.get_rw_from_interrupt();

    let v1 = r.read();

    w.write(5);
    let v2 = r.read();

    println!("v1: {}, v2: {}, t: {:?}", v1, v2, element);
}