Multithreading 这种保护单个资源在Rust中使用的无锁结构是否正确?
我正在尝试创建一个可以通过多个线程封送资源使用的结构。我相信我已经找到了一个正确的实现,但我仍然在学习内存顺序等,所以我想确保我的推理是正确的 资源单元有三个操作(除创建外):Multithreading 这种保护单个资源在Rust中使用的无锁结构是否正确?,multithreading,rust,lock-free,Multithreading,Rust,Lock Free,我正在尝试创建一个可以通过多个线程封送资源使用的结构。我相信我已经找到了一个正确的实现,但我仍然在学习内存顺序等,所以我想确保我的推理是正确的 资源单元有三个操作(除创建外): try\u acquire,它尝试获取对资源的可变引用 try\u take,它尝试取出资源,使单元格为空 try_reserve,它在空单元格中为线程保留空间以放置新资源 为了实现这一点,我创建了一个包含UnsafeCell的结构,其中包含三种可能的状态 const EMPTY: usize = 0; const
,它尝试获取对资源的可变引用try\u acquire
,它尝试取出资源,使单元格为空try\u take
,它在空单元格中为线程保留空间以放置新资源try_reserve
UnsafeCell
的结构,其中包含三种可能的状态
const EMPTY: usize = 0;
const FULL: usize = 1;
const IN_USE: usize = 2;
pub struct ResourceCell<T: Send> {
status: AtomicUsize,
resource: UnsafeCell<Option<T>>,
}
我对rust了解不够,无法对代码进行评论,但可能也能提供帮助?我认为
ResourceCell
本质上等同于Mutex
?@trentcl是的,本质上是一样的,只是你不必锁定它来判断它是否为空。
pub fn try_acquire(&self) -> Result<Guard<T>, ()> {
if self.status.compare_and_swap(FULL, IN_USE, Ordering::Acquire) == IN_USE {
// A Guard allows mutable access to the resource for its lifetime
// then when dropped, it calls status.store(FULL, Ordering::Release);
return Ok(Guard(self))
}
Err(())
}
pub fn try_take(&self) -> Result<T, ()> {
if self.status.compare_and_swap(FULL, IN_USE, Ordering::Acquire) == IN_USE {
let value = self.resource.get().take().unwrap();
self.cell.status.store(EMPTY, Ordering::Release);
return Ok(value);
}
Err(())
}
pub fn try_reserve(&self) -> Result<Reserve<T>, ()> {
if self.status.compare_and_swap(EMPTY, IN_USE, Ordering::Acquire) == IN_USE {
// A Reserve has a single method that consumes itself and places a new
// value in the resource cell, then calls status.store(FULL, Ordering::Release);
return Ok(Reserve(self))
}
Err(())
}
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::UnsafeCell;
const EMPTY: usize = 0;
const FULL: usize = 1;
const IN_USE: usize = 2;
pub struct ResourceCell<T: Send> {
status: AtomicUsize,
resource: UnsafeCell<Option<T>>,
}
impl<T: Send> ResourceCell<T> {
pub fn new(data: Option<T>) -> ResourceCell<T> {
ResourceCell {
status: AtomicUsize::new(if data.is_none() { EMPTY } else { FULL }),
resource: UnsafeCell::new(data)
}
}
pub fn try_acquire(&self) -> Result<Guard<T>, ()> {
if self.status.compare_and_swap(FULL, IN_USE, Ordering::Acquire) == IN_USE {
return Ok(Guard(self, FULL))
}
Err(())
}
pub fn try_take(&self) -> Result<T, ()> {
if self.status.compare_and_swap(FULL, IN_USE, Ordering::Acquire) == IN_USE {
let value = unsafe { self.resource.get().as_mut().unwrap().take().unwrap() };
self.status.store(EMPTY, Ordering::Release);
return Ok(value);
}
Err(())
}
pub fn try_reserve(&self) -> Result<Reserve<T>, ()> {
if self.status.compare_and_swap(EMPTY, IN_USE, Ordering::Acquire) == IN_USE {
return Ok(Reserve(self))
}
Err(())
}
}
unsafe impl<T: Send> Sync for ResourceCell<T> { }
pub struct Guard<'a, T: Send + 'a>(&'a ResourceCell<T>, usize);
impl<'a, T: Send + 'a> Guard<'a, T> {
pub fn take(mut self) -> T {
let value = unsafe { self.0.resource.get().as_mut().unwrap().take().unwrap() };
self.1 = EMPTY;
return value;
}
}
impl<'a, T: Send + 'a> Drop for Guard<'a, T> {
fn drop(&mut self) {
self.0.status.store(self.1, Ordering::Release);
}
}
impl<'a, T: Send + 'a> Deref for Guard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
return unsafe { self.0.resource.get().as_ref().unwrap().as_ref().unwrap() };
}
}
impl<'a, T: Send + 'a> DerefMut for Guard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
return unsafe { self.0.resource.get().as_mut().unwrap().as_mut().unwrap() };
}
}
pub struct Reserve<'a, T: Send + 'a>(&'a ResourceCell<T>);
impl<'a, T: Send + 'a> Reserve<'a, T> {
pub fn fill(self, value: T) {
unsafe { *self.0.resource.get().as_mut().unwrap() = Some(value) };
self.0.status.store(FULL, Ordering::Release);
}
}