#collection #cell #access #individual #lock #write #read

nightly lockerroom

为您的集合中单个单元格提供读写访问!

3个不稳定版本

0.2.1 2024年7月25日
0.2.0 2024年7月19日
0.1.0 2024年7月16日

268数据结构

Download history 238/week @ 2024-07-15 136/week @ 2024-07-22 17/week @ 2024-07-29

每月下载量 391

MIT 协议

51KB
798 行代码(不包括注释)

Locker Room

为您的集合中单个单元格提供读写访问!

LockerRoom 和 LockerRoomAsync

该crate的核心功能由这些结构实现。更具体地说,它们提供了以下功能

  1. 使用 LockerRoom::read_cellLockerRoomAsync::read_cell 提供对集合单个单元格的共享读取访问;
  2. 使用 LockerRoom::write_cellLockerRoomAsync::write_cell 提供对集合单个单元格的独占写入访问;
  3. 使用 LockerRoom::lock_roomLockerRoomAsync::lock_room 提供对整个集合的独占写入访问。

LockerRoomAsync 是可选的 - 您需要启用 async 功能才能使用它。它依赖于 tokioRwLock

LockerRoom 示例

let v = vec![0, 1, 2, 3, 4, 5];
let locker_room: LockerRoom<_> = v.into();
let locker_room = Arc::new(locker_room);
thread::scope(|scope| {
    scope.spawn(|| *locker_room.write_cell(0).unwrap() += 1);
    scope.spawn(|| *locker_room.write_cell(0).unwrap() += 2);
});
assert_eq!(3, *locker_room.read_cell(0).unwrap());

LockerRoomAsync 示例

let v = vec![0, 1, 2, 3, 4, 5];
let locker_room: LockerRoomAsync<_> = v.into();
let locker_room = Arc::new(locker_room);

let locker_room_cloned = Arc::clone(&locker_room);
let join1 = spawn(async move { *locker_room_cloned.write_cell(0).await.unwrap() += 1 });

let locker_room_cloned = Arc::clone(&locker_room);
let join2 = spawn(async move { *locker_room_cloned.write_cell(0).await.unwrap() += 2 });

join!(join1, join2);
assert_eq!(3, *locker_room.read_cell(0).await.unwrap());

死锁示例

小心在单个作用域中阻塞多个单元格。否则,可能会出现这种情况

// Thread 1                            |  // Thread 2
let _w1 = locker_room.write_cell(0);   |
                                       |  let _w1 = locker_room.write_cell(1);
// will block
let _w2 = locker_room.write_cell(1);   |
                                       |  // will deadlock
                                       |  let _w2 = locker_room.write_cell(0);

集合?

默认情况下,您可以从 arrayVecVecDequeHashMapBTreeMap 创建 LockerRoomLockerRoomAsync

但是,该crate提供了一些特质,通过实现这些特质,您可以使您的集合与 LockerRoomLockerRoomAsync 兼容。

集合

该crate的关键部分,帮助您的集合与 LockerRoomLockerRoomAsync 兼容。

只需将其实现到您的集合中,一切都会正常工作!

示例

让我们为 Index示例 中的结构实现该特质

enum Nucleotide {
    C,
    A,
    G,
    T,
}

struct NucleotideCount {
    pub a: usize,
    pub c: usize,
    pub g: usize,
    pub t: usize,
}

impl Collection for NucleotideCount {
    type Output = usize;
    type Idx = Nucleotide;
    type ShadowLocks = NucleotideShadowLocks;

    fn index(&self, index: impl Borrow<Self::Idx>) -> Option<&Self::Output> {
        Some(match index.borrow() {
            Nucleotide::A => &self.a,
            Nucleotide::C => &self.c,
            Nucleotide::G => &self.g,
            Nucleotide::T => &self.t,
        })
    }

    fn index_mut(&mut self, index: impl Borrow<Self::Idx>) -> Option<&mut Self::Output> {
        Some(match index.borrow() {
            Nucleotide::A => &mut self.a,
            Nucleotide::C => &mut self.c,
            Nucleotide::G => &mut self.g,
            Nucleotide::T => &mut self.t,
        })
    }

    fn indices(&self) -> impl Iterator<Item = Self::Idx> {
        [Nucleotide::A, Nucleotide::C, Nucleotide::G, Nucleotide::T].into_iter()
    }

    fn shadow_locks(&self) -> Self::ShadowLocks {
        Default::default()
    }
}

struct NucleotideShadowLocks {
    a: RwLock<()>,
    c: RwLock<()>,
    g: RwLock<()>,
    t: RwLock<()>,
}

impl ShadowLocksCollection for NucleotideShadowLocks {
    type Idx = Nucleotide;

    fn index(&self, index: impl Borrow<Self::Idx>) -> Option<&RwLock<()>> {
        Some(match index.borrow() {
            Nucleotide::A => &self.a,
            Nucleotide::C => &self.c,
            Nucleotide::G => &self.g,
            Nucleotide::T => &self.t,
        })
    }

    fn update_indices(&mut self, _indices: impl Iterator<Item = Self::Idx>) {
        // No need to reindex because NucleotideShadowLocks has static structure.
    }
}

如果启用功能 async,则 Collection 必须包括 Collection::ShadowLocksAsync 类型和 Collection::shadow_locks_async 方法。因此,必须实现 ShadowLocksCollectionAsync

impl Collection for NucleotideCount {
    // ...
    type ShadowLocksAsync = NucleotideShadowLocksAsync;
    // ...
    fn shadow_locks_async(&self) -> Self::ShadowLocksAsync {
        Default::default()
    }
}

struct NucleotideShadowLocksAsync {
    a: tokio::sync::RwLock<()>,
    c: tokio::sync::RwLock<()>,
    g: tokio::sync::RwLock<()>,
    t: tokio::sync::RwLock<()>,
}

impl ShadowLocksCollectionAsync for NucleotideShadowLocksAsync {
    type Idx = Nucleotide;

    fn index(&self, index: impl Borrow<Self::Idx>) -> Option<&tokio::sync::RwLock<()>> {
        Some(match index.borrow() {
            Nucleotide::A => &self.a,
            Nucleotide::C => &self.c,
            Nucleotide::G => &self.g,
            Nucleotide::T => &self.t,
        })
    }

    fn update_indices(&mut self, _indices: impl Iterator<Item = Self::Idx>) {
        // No need to reindex because NucleotideShadowLocksAsync has static structure.
    }
}

依赖项

~0–1.1MB
~19K SLoC