自旋锁(Spinlock)

我们实现的自旋锁的定义如下:

1
2
3
4
5
6
7
#[derive(Debug,Default)]
pub struct Spinlock<T: ?Sized>{
locked:AtomicBool,
name: &'static str,
cpu_id: Cell<isize>,
data:UnsafeCell<T>,
}

lockedcore::atmoic::AtomicBool来声明,这是一个原子布尔类型,即这是一个线程安全的值。而data的值则有UnsafeCell来包裹(wrap),这表明将有一些不安全的操作将作用在内部包裹的值中,使用该类型我们将没有办法获取内部变量的可变引用。我们可以通过.get()方法获取*mut T来对其内部进行操作。

对于一个锁变量,我们需要对其实现acquire()release()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pub fn acquire(&self) -> SpinlockGuard<'_, T> {

push_off();
if self.holding() {
panic!("acquire");
}

while self.locked.swap(true, Ordering::Acquire){
// Now we signals the processor that it is inside a busy-wait spin-loop
spin_loop();
}
fence(Ordering::SeqCst);
unsafe {
self.cpu_id.set(cpuid() as isize);
}

SpinlockGuard{spinlock: &self}
}

pub fn release(&self) {
if !self.holding() {
panic!("release");
}
self.cpu_id.set(-1);
fence(Ordering::SeqCst);
self.locked.store(false, Ordering::Release);

pop_off();
}

在我们的实现中,对于acquire方法,我们首先需要关闭中断并等待获取锁变量并对其进行原子上锁操作,在对变量上锁之后返回一个SpinlockGuard变量。

而对于release方法,我们则首先需要判断当前锁的状态,当锁为acquire状态时我们将其解锁并进行开启中断。

SpinlockGuard的定义如下:

1
2
3
pub struct SpinlockGuard<'a, T>{
spinlock:&'a Spinlock<T>
}

锁守卫者返回一个锁变量供获得锁的线程进行操作。同时我们对解引用操作符进行重载,从而能够使得获得锁的线程调用data的方法进行操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
impl<T> Deref for SpinlockGuard<'_, T>{
type Target = T;

fn deref(&self) -> &Self::Target {
unsafe{
&*self.spinlock.data.get()
}
}
}

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

睡眠锁(Sleeplock)

待开发…