rust 如何实现SpinLock

jfewjypa  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(136)

我试图实现我自己的自定义SpinLock,但SpinLock似乎行为不端。
我有两个文件,main.rssafe.rs
测试在Ubuntu 22.04.3LTS中完成,系统规格为4GB RAM,64位处理器,AMD® Pro a4- 3350 b APU和Radeon r4显卡。
下面是错误消息:

loki@loki:~/main/vs/actic/rust-nomic/spin-lock$ cargo run RUST_BACKTRACE=1
   Compiling spin-lock v0.1.0 (/home/loki/main/vs/actic/rust-nomic/spin-lock)
    Finished dev [unoptimized + debuginfo] target(s) in 0.98s
     Running `target/debug/spin-lock RUST_BACKTRACE=1`
Hello, world!
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `9999995`,
 right: `10000000`', src/main.rs:15:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

字符串
safe.rs

use core::ops::{Deref,DerefMut};
use core::sync::atomic::{AtomicBool,Ordering::{Acquire,Release}};
use core::cell::UnsafeCell;
use core::hint::spin_loop;

#[derive(Debug)]
pub struct SpinLock<T>{
    // Status true -> its locked ||  Status false -> its un_locked(ready to lock)
    status:AtomicBool,
    pub data:UnsafeCell<T>
}

pub struct SpinGuard<'a,T>{
    lock:&'a SpinLock<T>
}
unsafe impl<T> Sync for SpinLock<T> where T:Send{}

impl<T> SpinLock<T>{
    #[inline]
    pub const fn new(data:T)->Self{
        Self { status: AtomicBool::new(false), data: UnsafeCell::new(data) }
    }
    pub fn lock(&self)->SpinGuard<T>{
        while self.status.swap(true,Acquire){
            spin_loop();
        }
        SpinGuard { lock: self }
    }
}

impl<'a,T> SpinGuard<'a,T>{
    pub fn release(self){
        self.lock.status.store(false, Release)
    }
}

impl<T> Deref for SpinGuard<'_,T>{
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe{&*self.lock.data.get()}
    }
}

impl<T> DerefMut for SpinGuard<'_,T>{
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe{&mut *self.lock.data.get()}
    }
}

impl<T> Drop for SpinGuard<'_,T>{
    fn drop(&mut self) {
        self.lock.status.store(false, Release)
    }
}


main.rs

use std::thread;
mod safe;
fn main() {
    println!("Hello, world!");
    let mut  x=safe::SpinLock::new(0);
    thread::scope(|t|{
        for _  in 0..10000000{
            t.spawn(||{
                let mut q=x.lock();
                *q+=1;
                q.release();
            });
        }
    });
    assert_eq!(x.data.get_mut(),&mut 10000000);
    println!("{:?}",x);
}

4ktjp1zp

4ktjp1zp1#

通过添加几个sleep,您可以使错误更具可重复性:

use std::thread;

fn main() {
    println!("Hello, world!");
    let mut x = safe::SpinLock::new(0);
    thread::scope(|t| {
        for _ in 0..100 {
            t.spawn(|| {
                let mut q = x.lock();
                let q_prev = *q;
                std::thread::sleep(std::time::Duration::from_millis(1));
                *q = q_prev + 1;
                q.release();
            });
        }
    });
    assert_eq!(x.data.get_mut(), &mut 100);
    println!("{:?}", x.data.get_mut());
}

mod safe {
    use core::cell::UnsafeCell;
    use core::hint::spin_loop;
    use core::ops::{Deref, DerefMut};
    use core::sync::atomic::{
        AtomicBool,
        Ordering::{Acquire, Release},
    };

    #[derive(Debug)]
    pub struct SpinLock<T> {
        // Status true -> its locked ||  Status false -> its un_locked(ready to lock)
        status: AtomicBool,
        pub data: UnsafeCell<T>,
    }

    pub struct SpinGuard<'a, T> {
        lock: &'a SpinLock<T>,
    }
    unsafe impl<T> Sync for SpinLock<T> where T: Send {}

    impl<T> SpinLock<T> {
        #[inline]
        pub const fn new(data: T) -> Self {
            Self {
                status: AtomicBool::new(false),
                data: UnsafeCell::new(data),
            }
        }
        pub fn lock(&self) -> SpinGuard<T> {
            while self.status.swap(true, Acquire) {
                spin_loop();
            }
            SpinGuard { lock: self }
        }
    }

    impl<'a, T> SpinGuard<'a, T> {
        pub fn release(self) {
            self.lock.status.store(false, Release);
            std::thread::sleep(std::time::Duration::from_millis(1));
        }
    }

    impl<T> Deref for SpinGuard<'_, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            unsafe { &*self.lock.data.get() }
        }
    }

    impl<T> DerefMut for SpinGuard<'_, T> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            unsafe { &mut *self.lock.data.get() }
        }
    }

    impl<T> Drop for SpinGuard<'_, T> {
        fn drop(&mut self) {
            self.lock.status.store(false, Release)
        }
    }
}

个字符
原因是你解锁了两次,这有点隐藏,但.release()函数实际上直接解锁了一次,在drop()函数中解锁了一次。
只需删除.release()函数中的第一个解锁,然后它就可以工作了:)
作为另一个吹毛求疵的人,我会用AcqRel替换swap中的Acquire,但我不能100%肯定这会有什么不同。

use std::thread;

fn main() {
    println!("Hello, world!");
    let mut x = safe::SpinLock::new(0);
    thread::scope(|t| {
        for _ in 0..100 {
            t.spawn(|| {
                let mut q = x.lock();
                let q_prev = *q;
                std::thread::sleep(std::time::Duration::from_millis(1));
                *q = q_prev + 1;
                q.release();
            });
        }
    });
    assert_eq!(x.data.get_mut(), &mut 100);
    println!("{:?}", x.data.get_mut());
}

mod safe {
    use core::cell::UnsafeCell;
    use core::hint::spin_loop;
    use core::ops::{Deref, DerefMut};
    use core::sync::atomic::{
        AtomicBool,
        Ordering::{AcqRel, Release},
    };

    #[derive(Debug)]
    pub struct SpinLock<T> {
        // Status true -> its locked ||  Status false -> its un_locked(ready to lock)
        status: AtomicBool,
        pub data: UnsafeCell<T>,
    }

    pub struct SpinGuard<'a, T> {
        lock: &'a SpinLock<T>,
    }
    unsafe impl<T> Sync for SpinLock<T> where T: Send {}

    impl<T> SpinLock<T> {
        #[inline]
        pub const fn new(data: T) -> Self {
            Self {
                status: AtomicBool::new(false),
                data: UnsafeCell::new(data),
            }
        }
        pub fn lock(&self) -> SpinGuard<T> {
            while self.status.swap(true, AcqRel) {
                spin_loop();
            }
            SpinGuard { lock: self }
        }
    }

    impl<'a, T> SpinGuard<'a, T> {
        pub fn release(self) {
            // Nothing to do here, `drop` will perform the unlock
        }
    }

    impl<T> Deref for SpinGuard<'_, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            unsafe { &*self.lock.data.get() }
        }
    }

    impl<T> DerefMut for SpinGuard<'_, T> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            unsafe { &mut *self.lock.data.get() }
        }
    }

    impl<T> Drop for SpinGuard<'_, T> {
        fn drop(&mut self) {
            self.lock.status.store(false, Release)
        }
    }
}
Hello, world!
100

的字符串

相关问题