parking_lot 文档说 'allow raw (un)locking without a RAII guard object' 是什么意思?

What does the parking_lot documentation mean when it says 'allow raw (un)locking without a RAII guard object'?

docs for parking_lot 说:

  1. Mutex and RwLock allow raw unlocking without a RAII guard object.
  2. Mutex<()> and RwLock<()> allow raw locking without a RAII guard object.

没有进一步提及这些功能、它们的含义以及如何使用它们。有哪些指示或示例用途?

Rust 保证安全代码不会包含数据竞争(对同一对象的并发可变访问)。互斥体允许线程对 read/write 对象进行互斥访问,从而避免竞争。

在其他语言中,(Java 和 C++ 浮现在脑海中)互斥与数据没有显式关联。程序员需要确保他们正确地锁定和解锁它们,只访问锁定和解锁之间的关键部分内的数据。在 Rust 中,这意味着如果编写不正确,安全代码可能包含数据竞争。

解决这个问题的方法是 RAII 守卫。互斥锁“拥有”关联的对象,并且只允许 read/write 通过代表互斥锁锁的 RAII 守卫进行访问。这是 std 的 Mutex::lock()

返回的 MutexGuard 类型

Parking_lot 声称允许 locking/unlocking 无需创建 RAII 守卫,这在编写不安全的代码时非常有用,因为速度原因使用互斥体做一些奇特的事情。这与不提供这些方法的标准 sync::Mutex 不同。

RAII 守卫的主要限制是,根据 RAII 的性质,它们只能持续到封闭范围。此外,它们持有对互斥量的引用,因此由于 Rust 的借用规则,很难将“锁”“存储”到其范围之外。

引用的parking_lot方法是不安全的raw_unlock和安全的raw_lock。由于 raw_lock() 需要关联的 raw_unlock() 来完成临界区,使用这些功能意味着深入研究不安全的代码,这通常是 ill-advised 并且没有必要,除非您有充分的理由相信它是完成您需要的唯一方法。

Mutex API 通过守卫控制对其数据的访问,当它超出范围时解锁 MutexMutex 拥有它的数据,并且可以强制只有在它被锁定时才能通过 MutexGuard 访问它。 std::sync::Mutexparking_lot::Mutex在这方面是一样的。

但是,parking_lot::Mutex 也公开了它的内部结构,即指向数据的原始指针和 RawMutexRawMutex只是一把锁,它不控制对数据的访问,只是跟踪锁的状态。

使用 RawMutex 的一个原因可能是有时在范围内保持 MutexGuard 非常不方便,并且您准备好自己管理锁定状态。这更有可能出现在定义新的同步原语或智能指针的库中,而不是应用程序代码中,但如果您将现有的 C/C++ 代码机械地转换为 Rust,您可能也会发现它很有用。

举个简单的例子,这些函数彼此做同样的事情,但是其中一个使用了不安全的 RawMutex:

use parking_lot::{Mutex, lock_api::RawMutex as _};

fn update_mutex(mutex: &Mutex<i32>) {
    let mut guard = mutex.lock();
    *guard = 2;
    // guard goes out of scope here, causing the Mutex to be unlocked
}

fn update_mutex_raw(mutex: &Mutex<i32>) {
    let raw_mutex = unsafe { mutex.raw() };
    let data = mutex.data_ptr();
    raw_mutex.lock();
    unsafe { 
        *data = 2;
        // need to manually unlock the RawMutex
        raw_mutex.unlock();  
    };
}

RawMutex.unlock() 是不安全的,因为它会在 murex 未锁定时触发未定义行为来调用它。一次取消引用数据指针两次也是未定义的行为,因此您可以通过遵守 RawMutex.

的锁定状态来确保您不这样做。

与往常一样,在使用 unsafe 函数时,请仔细阅读文档并确保您彻底理解为避免未定义行为而必须保留的不变量。