#lock #mutex #deadlock #derive #locking #sync #deadlocker

deadlocker_derive

#[derive(Locker)]宏的实现

1 个不稳定版本

0.1.0 2024年5月22日

#19 in #deadlock


deadlocker中使用

MIT许可证

23KB
468

Deadlocker

Deadlocker是一个旨在以构建者模式灵感消除死锁的crate


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

  1. 为每种可能持有的锁的组合创建一个结构体
  2. 为在原始结构体中持有锁的引用创建一个结构体
  3. 允许锁器结构体按任意顺序链式调用方法来指定所需的锁
  4. 在锁器结构体上实现一个最终锁定方法,它将以确定性的顺序锁定所需的锁,消除由于锁获取顺序不当而导致的死锁

示例

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的补充,通常只指定其中一个,此属性具有优先权。

#[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

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

#[include]

exclude

指示此字段不应包含在锁结构体中。如果有一个大型状态结构体,其中大多数字段都是锁,则非常有用。

#[exclude]

依赖关系

~2.8–4.5MB
~79K SLoC