Struct cros_async::sync::mu::RwLock
source · #[repr(align(128))]pub struct RwLock<T: ?Sized> {
raw: RawRwLock,
value: UnsafeCell<T>,
}
Expand description
A high-level primitive that provides safe, mutable access to a shared resource.
RwLock
safely provides both shared, immutable access (via read_lock()
) as well as exclusive,
mutable access (via lock()
) to an underlying resource asynchronously while ensuring fairness
with no loss of performance. If you don’t need read_lock()
nor fairness, try upstream
futures::lock::Mutex
instead.
§Poisoning
RwLock
does not support lock poisoning so if a thread panics while holding the lock, the
poisoned data will be accessible by other threads in your program. If you need to guarantee that
other threads cannot access poisoned data then you may wish to wrap this RwLock
inside another
type that provides the poisoning feature. See the implementation of std::sync::Mutex
for an
example of this. Note futures::lock::Mutex
does not support poisoning either.
§Fairness
This RwLock
implementation does not guarantee that threads will acquire the lock in the same
order that they call lock()
or read_lock()
. However it will attempt to prevent long-term
starvation: if a thread repeatedly fails to acquire the lock beyond a threshold then all other
threads will fail to acquire the lock until the starved thread has acquired it. Note, on the
other hand, futures::lock::Mutex
does not guarantee fairness.
Similarly, this RwLock
will attempt to balance reader and writer threads: once there is a
writer thread waiting to acquire the lock no new reader threads will be allowed to acquire it.
However, any reader threads that were already waiting will still be allowed to acquire it.
§Examples
use std::sync::Arc;
use std::thread;
use std::sync::mpsc::channel;
use cros_async::{block_on, sync::RwLock};
const N: usize = 10;
// Spawn a few threads to increment a shared variable (non-atomically), and
// let the main thread know once all increments are done.
//
// Here we're using an Arc to share memory among threads, and the data inside
// the Arc is protected with a rwlock.
let data = Arc::new(RwLock::new(0));
let (tx, rx) = channel();
for _ in 0..N {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
// The shared state can only be accessed once the lock is held.
// Our non-atomic increment is safe because we're the only thread
// which can access the shared state when the lock is held.
let mut data = block_on(data.lock());
*data += 1;
if *data == N {
tx.send(()).unwrap();
}
// the lock is unlocked here when `data` goes out of scope.
});
}
rx.recv().unwrap();
Fields§
§raw: RawRwLock
§value: UnsafeCell<T>
Implementations§
source§impl<T> RwLock<T>
impl<T> RwLock<T>
sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
Consume the RwLock
and return the contained value. This method does not perform any
locking as the compiler will guarantee that there are no other references to self
and the
caller owns the RwLock
.
source§impl<T: ?Sized> RwLock<T>
impl<T: ?Sized> RwLock<T>
sourcepub async fn lock(&self) -> RwLockWriteGuard<'_, T>
pub async fn lock(&self) -> RwLockWriteGuard<'_, T>
Acquires exclusive, mutable access to the resource protected by the RwLock
, blocking the
current thread until it is able to do so. Upon returning, the current thread will be the
only thread with access to the resource. The RwLock
will be released when the returned
RwLockWriteGuard
is dropped.
Calling lock()
while holding a RwLockWriteGuard
or a RwLockReadGuard
will cause a
deadlock.
Callers that are not in an async context may wish to use the block_on
method to block the
thread until the RwLock
is acquired.
sourcepub async fn read_lock(&self) -> RwLockReadGuard<'_, T>
pub async fn read_lock(&self) -> RwLockReadGuard<'_, T>
Acquires shared, immutable access to the resource protected by the RwLock
, blocking the
current thread until it is able to do so. Upon returning there may be other threads that
also have immutable access to the resource but there will not be any threads that have
mutable access to the resource. When the returned RwLockReadGuard
is dropped the thread
releases its access to the resource.
Calling read_lock()
while holding a RwLockReadGuard
may deadlock. Calling read_lock()
while holding a RwLockWriteGuard
will deadlock.
Callers that are not in an async context may wish to use the block_on
method to block the
thread until the RwLock
is acquired.