1 个不稳定版本

0.1.0 2024年5月22日

#680Rust 模式

MIT 许可证

8KB

Deadlocker

Deadlocker 是一个旨在以构建器模式启发的方式消除死锁的 crate


该 crate 的主要功能是 derive 宏,它将执行以下操作:

  1. 为每个可能持有的锁的组合创建一个 struct
  2. 为包含原始 struct 中锁引用的 struct 创建一个 struct
  3. 允许 locker struct 连接方法以指定所需的锁,顺序可任意
  4. 在 locker struct 上实现一个最终的锁定方法,该方法将以确定性的顺序锁定所需的锁,消除由于锁定顺序不当而引起的死锁

示例

use deadlocker::Locker;
use std::sync::{Arc, Mutex};

type Foo = Vec<usize>;
type Bar = usize;
type Baz = u8;

#[derive(Locker)]
pub struct MyStruct {
    #[result]
    pub foo: Arc<Mutex<Foo>>,
    #[result]
    pub bar: Arc<Mutex<Bar>>,
    #[result]
    pub baz: Arc<Mutex<Baz>>,
}

pub fn main() {
    let mut my_struct = MyStruct {
        foo: Arc::new(Mutex::new(Vec::new())),
        bar: Arc::new(Mutex::new(0)),
        baz: Arc::new(Mutex::new(0)),
    };

    {
        let mut lock = my_struct
            .locker()
            .baz()
            .foo()
            .lock()
            .expect("Mutex was poisoned");

        lock.foo.push(1);
        **lock.baz = 1;
    }

    {
        let lock = my_struct
            .locker()
            .bar()
            .foo()
            .baz()
            .lock()
            .expect("Mutex was poisoned");

        println!("Foo: {:?}", **lock.foo);
        println!("Bar: {:?}", **lock.bar);
        println!("Baz: {:?}", **lock.baz);
    }
}

属性

每个字段都可以使用多个属性来修改 derive 宏的行为。效果如下,示例在 示例目录 中提供

outer_type

指示外部类型,即锁定部分,与 inner_type 相对应。这是 inner_type 的补充,通常只指定其中一个,而 inner_type 优先。

它使用正则表达式指定,其中只有一个捕获组,其中 inner_type 应该存在。指定外部类型主要在内部类型长而复杂时有用。

#[outer_type = "Arc<Mutex<(.*)>>"]

注意,这默认设置为上述内容,这意味着如果您的字段符合该模式,您不需要指定任何内容。请参阅 基本示例 了解更多。

inner_type

指示内部类型,即被锁保护的类型。这是 outer_type 的补充,通常只指定其中一个,且此优先于 outer_type

#[inner_type = "usize"]

async_lock

将锁标记为异步,这会导致包含一个标记为async_lock字段的链中的最终lock方法也变为异步。这不会影响结构体中的其他锁,因此最终lock方法不必因为有些锁是异步的而本身也必须是异步的。

#[async_lock]

lock_method

指示如何从锁访问inner_type。对于std::sync::Mutex,这是lock(),而对于tokio::sync::Mutex,它是lock().await。注意省略了前面的点号以及后面的分号。

#[lock_method = "lock()"]

对于同步锁,这默认为lock(),对于异步锁,则为lock().await,这意味着大多数人不需要指定这个。

result

将锁标记为在其保护器上产生结果,而不是直接产生保护器。这对于std::sync::Mutex是正确的,但对于tokio::sync::Mutex则不是。这会导致包含一个标记为result字段的链中的最终lock方法返回一个结果,通常返回的结构体被嵌入其Ok变体中。

#[result]

include

指示此字段应包含在locker结构体中。只有一个字段被标记为这样的字段存在意味着没有标记的字段不应被包含。如果有一个大的状态结构体,其中只有一小部分是锁,这很有用。这覆盖了任何exclude属性。

#[include]

exclude

指示此字段不应包含在locker结构体中。如果有一个大的状态结构体,其中大部分字段都是锁,这很有用。

#[exclude]

依赖关系

~0–640KB
~12K SLoC