1 个不稳定版本
| 0.1.0 | 2022年12月8日 |
|---|
#689 在 并发
53KB
718 行
cell-family
受 qcell::TCell / qcell::TLCell 启发,具有额外功能。
概述
cell-family 提供了 define! 宏,用于定义一个新的 Family。对于每个家族,可以创建相应的 Cell 和 CellOwner。每个家族只能存在一个 CellOwner,但可以同时存在多个单元格。
例如,您可能如下定义一个家族 FooFamily
cell_family::define!(type FooFamily: FooCellOwner for FooCell<T>);
这定义了 FooFamily(实现了 Family)以及 FooCellOwner 和 FooCell,分别是 CellOwner<FooFamily> 和 Cell<FooFamily> 的别称。
每个线程可以存在一个 FooCellOwner,因此 FooCellOwner 是 不 Send,因为将 FooCellOwner 发送到另一个线程可能会允许在单个线程中存在两个 FooCellOwner。要允许每个程序存在一个 FooCellOwner(并使 FooCellOwner 成为 Send),请在 define! 前面加上 static
cell_family::define!(static type FooFamily: FooCellOwner for FooCell<T>);
对于线程局部和线程安全的家族,API 是相同的
let mut owner = FooCellOwner::new();
let a = FooCell::new(1);
let b = FooCell::new("bar");
assert_eq!(*a.get(&owner), 1);
assert_eq!(*b.get(&owner), "bar");
*a.get_mut(&mut owner) += 1;
*b.get_mut(&mut owner) = "baz";
assert_eq!(*a.get(&owner), 2);
assert_eq!(*b.get(&owner), "baz");
FooCell::new(T)简单地将T包装在#[repr(transparent)]FooCell中,而不执行任何检查。FooCell::get(&FooCellOwner)和FooCell::get_mut(&mut FooCellOwner)是常数时间操作,分别返回&T和&mut T而不执行任何运行时检查。由于每个程序(或线程)只有一个FooCellOwner存在,Rust 通过FooCellOwner强制执行每个单元的别名规则,只要每个FooCell被借用,FooCellOwner就会被借用。FooFamily确保程序中存在单个FooCellOwner;如果存在另一个FooCellOwner,FooCellOwner::new()将会引发 panic。为了避免这种情况崩溃,存在一个try_new()对应方法。
相对于 qcell::TCell / qcell::TLCell 的优势
-
与
qcell::TCell(分别qcell::TCell)不同,FamilyF负责确保程序(分别线程)中存在单个CellOwner<F>。通过使用宏来生成家族,我们只需要为每个家族提供一个AtomicBool(分别Cell<bool>),因此不需要分配。 -
提供了一些额外的方法;例如,
owner.get(c),owner.get_mut(c)和owner.try_get_mut(c),其中c可以是 -
线程局部和线程安全的
Cell(以及CellOwner)由相同类型支持;它们是线程局部还是线程安全由它们的Family决定:如果是线程安全的,它也将实现ThreadSafeFamily。这使得在Cell上定义泛型函数更加容易。 -
cell-family完全支持#[no_std],但不包括非nightly构建中的线程局部家族(因为在不使用#[thread_local]的情况下无法在#[no_std]中定义线程局部变量,这还不稳定)。 -
Cell实现Debug,如果当前不存在CellOwner,将打印其内部值的表示。