The docs for parking_lot say:
Mutex
andRwLock
allow raw unlocking without a RAII guard object.Mutex<()>
andRwLock<()>
allow raw locking without a RAII guard object.
There is no further mention of these features, what they mean and how to use them. What are some pointers or sample uses?
The Mutex
API controls access to its data via a guard, which unlocks the Mutex
when it goes out of scope. The Mutex
owns its data and can enforce that it is only accessible through a MutexGuard
when it is locked. Both std::sync::Mutex
and parking_lot::Mutex
are the same in this regard.
However, parking_lot::Mutex
also exposes its internals, which are a raw pointer to the data and a RawMutex
. A RawMutex
is just a lock, which does not control access to the data, but just tracks the state of the lock.
One reason to use RawMutex
might be for times when it is very inconvenient to keep a MutexGuard
in scope, and you are prepared to manage the lock status yourself. This is more likely in a library that defines new synchronization primitives or smart pointers rather than in application code, but you might also find it useful if you were mechanically translating existing C/C++ code to Rust.
By way of a simple example, these functions do the same thing as each other, but one uses the unsafe 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()
is unsafe because it would trigger Undefined Behaviour to call it when the murex is not locked. Dereferencing the data pointer twice at once would be Undefined Behaviour too, so it's up to you to make sure you don't, by honouring the lock state of the RawMutex
.
As always, when using unsafe
functions, read the documentation carefully and make sure you thoroughly undersand the invariants that you must preserve in order to avoid Undefined Behaviour.