pub struct RwLock<T: ?Sized> { /* private fields */ }
Expand description
A reader-writer lock.
It behaves like std::sync::RwLock except for using spinlock.
What is more, the constructor is a const function; i.e. it is possible to declare
static RwLock<T>
variable as long as the inner data can be built statically.
This type of lock allows either a number of readers or at most one writer at the same time. Readers are allowed read-only access (shared access) to the underlying data while the writer is allowed read/write access (exclusive access.)
In comparison, a Mutex
does not distinguish between readers and writers,
therefore blocking any threads waiting for the lock to become available.
An RwLock
will allow any number of readers to acquire the lock as long as
a writer is not holding the lock.
There is no priority difference with respect to the ordering of whether contentious readers or writers will acquire the lock first.
§Poisoning
An RwLock
, like Mutex
, will become poisoned on a panic. Note, however,
that an RwLock
may only be poisoned if a panic occurs while it is locked
exclusively (write mode). If a panic occurs in any reader, then the lock
will not be poisoned.
§Examples
Create a variable protected by a RwLock, increment it by 2 in worker threads at the same time, and check the variable was updated rightly.
use spin_sync::RwLock;
use std::sync::Arc;
use std::thread;
const WORKER_NUM: usize = 10;
let mut handles = Vec::with_capacity(WORKER_NUM);
// We can declare static RwLock<usize> variable because RwLock::new is a const function.
static RWLOCK: RwLock<usize> = RwLock::new(0);
// Create worker threads to inclement the value by 2.
for _ in 0..WORKER_NUM {
let handle = thread::spawn(move || {
let mut num = RWLOCK.write().unwrap();
*num += 2;
});
handles.push(handle);
}
// Make sure the value is always multipile of 2 even if some worker threads
// are working.
//
// Enclosing the lock with `{}` to drop it before waiting for the worker
// threads; otherwise, deadlocks could be occurred.
{
let num = RWLOCK.read().unwrap();
assert_eq!(0, *num % 2);
}
// Wait for the all worker threads are finished.
for handle in handles {
handle.join().unwrap();
}
// Make sure the value is incremented by 2 times the worker count.
let num = RWLOCK.read().unwrap();
assert_eq!(2 * WORKER_NUM, *num);
Implementations§
Source§impl<T> RwLock<T>
impl<T> RwLock<T>
Sourcepub const fn new(t: T) -> Self
pub const fn new(t: T) -> Self
Creates a new instance in unlocked state ready for use.
§Examples
Declare as a static variable.
use spin_sync::RwLock;
static LOCK: RwLock<i32> = RwLock::new(5);
Declare as a local variable.
use spin_sync::RwLock;
let lock = RwLock::new(5);
Sourcepub fn into_inner(self) -> LockResult<T>
pub fn into_inner(self) -> LockResult<T>
Consumes this instance and returns the underlying data.
Note that this method won’t acquire any lock because we know there is
no other references to self
.
§Errors
If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.
§Examples
use spin_sync::RwLock;
let rwlock = RwLock::new(0);
assert_eq!(0, rwlock.into_inner().unwrap());
Source§impl<T: ?Sized> RwLock<T>
impl<T: ?Sized> RwLock<T>
Sourcepub const MAX_READ_LOCK_COUNT: u64 = 4_611_686_018_427_387_903u64
pub const MAX_READ_LOCK_COUNT: u64 = 4_611_686_018_427_387_903u64
The maximum shared read locks of each instance.
Sourcepub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>>
pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>>
Blocks the current thread until acquiring a shared read lock, and returns an RAII guard object.
The actual flow will be as follows.
- User calls this method.
- Blocks until this thread acquires a shared read lock (i.e. until the exclusive write lock is held.)
- Creates an RAII guard object.
- Wrapps the guard in
Result
and returns it. If this instance has been poisoned, it is wrapped in anErr
; otherwise wrapped in anOk
.
- User accesses to the underlying data to read through the guard. (No write access is then.)
- The guard is dropped (falls out of scope) and the lock is released.
§Errors
If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.
§Panics
This method panics if MAX_READ_LOCK_COUNT
shared locks are.
§Examples
use spin_sync::RwLock;
let lock = RwLock::new(1);
let guard1 = lock.read().unwrap();
assert_eq!(1, *guard1);
let guard2 = lock.read().unwrap();
assert_eq!(1, *guard2);
Sourcepub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>>
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>>
Attempts to acquire a shared read lock and returns an RAII guard object if succeeded.
Behaves like read
except for this method returns an error immediately
if the exclusive write lock is being held.
This function does not block.
The actual flow will be as follows.
- User calls this method.
- Tries to acquire a shared read lock. If failed (i.e. if the exclusive write lock is being held,) returns an error immediately and this flow is finished here.
- Creates an RAII guard object.
- Wrapps the guard in
Result
and returns it. If this instance has been poisoned, it is wrapped in anErr
; otherwise wrapped in anOk
.
- User accesses to the underlying data to read through the guard. (No write access is at then.)
- The guard is dropped (falls out of scope) and the lock is released.
§Panics
This method panics if MAX_READ_LOCK
shared read locks are.
§Errors
- If another user is holding the exclusive write lock,
TryLockError::WouldBlock
is returned. - If this method call succeeded to acquire a shared read lock, and if another
user had panicked while holding the exclusive write lock,
TryLockError::Poisoned
is returned.
§Examples
use spin_sync::RwLock;
let lock = RwLock::new(1);
let guard0 = lock.try_read().unwrap();
assert_eq!(1, *guard0);
let guard1 = lock.try_read().unwrap();
assert_eq!(1, *guard1);
Sourcepub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>>
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>>
Attempts to acquire the exclusive write lock and returns an RAII guard object if succeeded.
Behaves like write
except for this method returns an error immediately
if any other lock (either read lock or write lock) is being held.
This method does not block.
The actual flow will be as follows.
- User calls this method.
- Tries to acquire the exclusive write lock. If failed (i.e. if any other lock is being held,) returns an error immediately and this flow is finished here.
- Creates an RAII guard object.
- Wraps the guard in
Result
and returns it. If this instance has been poisoned, it is wrapped in anErr
; otherwise wrapped in anOk
.
- User accesses to the underlying data to read/write through the guard. (No other access is then.)
- The guard is dropped (falls out of scope) and the lock is released.
§Errors
- If another user is holding any other lock (either read lock or write lock),
TryLockError::WouldBlock
is returned. - If this method call succeeded to acquire the lock, and if another user had panicked
while holding the exclusive write lock,
TryLockError::Poisoned
is returned.
§Examples
use spin_sync::RwLock;
let lock = RwLock::new(1);
let mut guard = lock.try_write().unwrap();
assert_eq!(1, *guard);
*guard += 1;
assert_eq!(2, *guard);
assert!(lock.try_write().is_err());
assert!(lock.try_read().is_err());
Sourcepub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>>
pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>>
Blocks the current thread until acquiring the exclusive write lock, and returns an RAII guard object.
The actual flow will be as follows.
- User calls this method.
- Blocks until this thread acquires the exclusive write lock (i.e. until any other lock is held.)
- Creates an RAII guard object.
- Wrapps the guard in Result and returns it. If this instance has been
poisoned, it is wrapped in an
Err
; otherwise wrapped in anOk
.
- User accesses to the underlying data to read/write through the guard. (No other access is then.)
- The guard is dropped (falls out of scope) and the lock is released.
§Errors
If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.
§Examples
use spin_sync::RwLock;
let lock = RwLock::new(0);
let mut guard = lock.write().unwrap();
assert_eq!(0, *guard);
*guard += 1;
assert_eq!(1, *guard);
assert_eq!(true, lock.try_read().is_err());
assert_eq!(true, lock.try_write().is_err());
Sourcepub fn is_poisoned(&self) -> bool
pub fn is_poisoned(&self) -> bool
Determines whether the lock is poisoned or not.
§Warning
This function won’t acquire any lock. If another thread is active,
the rwlock can become poisoned at any time. You should not trust a false
value for program correctness without additional synchronization.
§Examples
use spin_sync::RwLock;
use std::sync::Arc;
use std::thread;
let lock = Arc::new(RwLock::new(0));
assert_eq!(false, lock.is_poisoned());
{
let lock = lock.clone();
let _ = thread::spawn(move || {
// This panic while holding the lock (`_guard` is in scope) will poison
// the instance.
let _guard = lock.write().unwrap();
panic!("Poison here");
}).join();
}
assert_eq!(true, lock.is_poisoned());
Sourcepub fn get_mut(&mut self) -> LockResult<&mut T>
pub fn get_mut(&mut self) -> LockResult<&mut T>
Returns a mutable reference to the underlying data.
Note that this method won’t acquire any lock because we know there is
no other references to self
.
§Errors
If another user panicked while holding the exclusive write lock of this instance, this method call wraps the guard in an error and returns it.
§Examples
use spin_sync::RwLock;
let mut lock = RwLock::new(0);
*lock.get_mut().unwrap() = 10;
assert_eq!(*lock.read().unwrap(), 10);