pub struct Locked<T>where
T: ?Sized,{ /* private fields */ }
Expand description
A value locked by a Lock
.
Objects of this type can be created with Lock::wrap
.
This object is essentially the same as the wrapped value with the following differences:
Locked<T>: Sync
if and only ifT: Send
.- Only one thread can access the contained value at a time.
This object derefs to the underlying Lock
.
§Example
use std::cell::Cell;
use std::sync::Arc;
use static_assertions::assert_impl_all;
use shared_lock::{Lock, Locked};
struct Context {
lock: Lock,
global_value: Locked<Cell<u64>>,
}
struct Child {
context: Arc<Context>,
local_value: Locked<Cell<u64>>,
}
impl Child {
fn increment(&self) {
let guard = &self.context.lock.lock();
let local_value = self.local_value.get(guard);
local_value.set(local_value.get() + 1);
let global_value = self.context.global_value.get(guard);
global_value.set(global_value.get() + 1);
}
}
assert_impl_all!(Context: Send, Sync);
assert_impl_all!(Child: Send, Sync);
let lock = Lock::default();
let context = Arc::new(Context {
global_value: lock.wrap(Cell::new(0)),
lock,
});
let child1 = Arc::new(Child {
context: context.clone(),
local_value: context.lock.wrap(Cell::new(0)),
});
let child2 = Arc::new(Child {
context: context.clone(),
local_value: context.lock.wrap(Cell::new(0)),
});
child1.increment();
child2.increment();
child2.increment();
let guard = &context.lock.lock();
assert_eq!(child1.local_value.get(guard).get(), 1);
assert_eq!(child2.local_value.get(guard).get(), 2);
assert_eq!(context.global_value.get(guard).get(), 3);
Implementations§
Source§impl<T> Locked<T>where
T: ?Sized,
impl<T> Locked<T>where
T: ?Sized,
Sourcepub fn get<'a>(&'a self, guard: &'a Guard<'_>) -> &'a T
pub fn get<'a>(&'a self, guard: &'a Guard<'_>) -> &'a T
Accesses the locked value.
The guard must be a guard created from the same Lock
that was used to create
this object. That is the same Lock
that this object Deref
s to.
This function performs only a single comparison and a jump, which makes it very fast and suitable for inner loops.
§Panic
Panics if the guard was not created from the same Lock
that was used to create
this object.
§Example
use shared_lock::Lock;
let lock = Lock::default();
let locked1 = lock.wrap(5);
let locked2 = lock.wrap(6);
let guard = &lock.lock();
assert_eq!(*locked1.get(guard), 5);
assert_eq!(*locked2.get(guard), 6);
Sourcepub fn into_inner(self) -> Twhere
T: Sized,
pub fn into_inner(self) -> Twhere
T: Sized,
Unwraps the value, consuming this object.
§Examples
use shared_lock::Lock;
let lock = Lock::default();
let locked = lock.wrap(5);
assert_eq!(locked.into_inner(), 5);
Methods from Deref<Target = Lock>§
Sourcepub unsafe fn force_unlock(&self)
pub unsafe fn force_unlock(&self)
Forcibly consumes a ticket.
This can be used to consume the ticket of a Guard
that was passed to
mem::forget
.
§Safety
- The current thread must own a ticket.
- The invariant that each
Guard
owns a ticket must be upheld whenever aGuard
is used or dropped.
§Example
use std::mem;
use shared_lock::Lock;
let lock = Lock::default();
let guard = lock.lock();
assert!(lock.is_locked());
mem::forget(guard);
// SAFETY: This consumes the ticket from the guard.
unsafe {
lock.force_unlock();
}
assert!(!lock.is_locked());
Sourcepub unsafe fn force_unlock_fair(&self)
pub unsafe fn force_unlock_fair(&self)
Forcibly consumes a ticket.
If this causes the number tickets to go to 0, the underlying mutex will be unlocked fairly.
This can be used to consume the ticket of a Guard
that was passed to
mem::forget
.
§Safety
- The current thread must own a ticket.
- The invariant that each
Guard
owns a ticket must be upheld whenever aGuard
is used or dropped.
§Example
use std::mem;
use shared_lock::Lock;
let lock = Lock::default();
let guard = lock.lock();
assert!(lock.is_locked());
mem::forget(guard);
// SAFETY: This consumes the ticket from the guard.
unsafe {
lock.force_unlock_fair();
}
assert!(!lock.is_locked());
Sourcepub fn is_locked(&self) -> bool
pub fn is_locked(&self) -> bool
Returns whether this lock is locked.
§Example
use shared_lock::Lock;
let lock = Lock::default();
assert!(!lock.is_locked());
let _guard = lock.lock();
assert!(lock.is_locked());
Sourcepub fn is_locked_by(&self, guard: &Guard<'_>) -> bool
pub fn is_locked_by(&self, guard: &Guard<'_>) -> bool
Returns whether this lock is locked by the guard.
§Example
use shared_lock::Lock;
let lock1 = Lock::default();
let lock2 = Lock::default();
let guard1 = &lock1.lock();
let guard2 = &lock2.lock();
assert!(lock1.is_locked_by(&guard1));
assert!(!lock1.is_locked_by(&guard2));
Sourcepub fn is_locked_by_current_thread(&self) -> bool
pub fn is_locked_by_current_thread(&self) -> bool
Returns whether the current thread is holding the lock.
§Example
use std::thread;
use shared_lock::Lock;
let lock = Lock::default();
let _guard = lock.lock();
assert!(lock.is_locked_by_current_thread());
thread::scope(|scope| {
let handle = scope.spawn(|| {
assert!(!lock.is_locked_by_current_thread());
});
handle.join().unwrap();
});
Sourcepub fn lock(&self) -> Guard<'_>
pub fn lock(&self) -> Guard<'_>
Acquires this lock.
If the lock is held by another thread, then this function will block until it is able to acquire the lock. If the current thread has already acquired the lock, the function returns immediately.
§Example
use shared_lock::Lock;
let lock = Lock::default();
let _guard = lock.lock();
Sourcepub unsafe fn make_guard_unchecked(&self) -> Guard<'_>
pub unsafe fn make_guard_unchecked(&self) -> Guard<'_>
Sourcepub fn try_lock(&self) -> Option<Guard<'_>>
pub fn try_lock(&self) -> Option<Guard<'_>>
Attempts to acquire this lock.
If the lock cannot be acquired at this time, None
is returned. Otherwise a guard
is returned and the lock will be unlocked when the guard is dropped.
This function does not block.
§Example
use std::thread;
use std::time::{Duration, Instant};
use shared_lock::Lock;
let timeout = Duration::from_millis(200);
let lock = Lock::default();
let _guard = lock.lock();
// The same thread can lock the lock again.
assert!(lock.try_lock().is_some());
thread::scope(|scope| {
let join_handle = scope.spawn(|| {
// Another thread cannot lock the lock.
assert!(lock.try_lock().is_none());
});
join_handle.join().unwrap();
});
Sourcepub fn try_lock_for(&self, duration: Duration) -> Option<Guard<'_>>
pub fn try_lock_for(&self, duration: Duration) -> Option<Guard<'_>>
Attempts to acquire this lock until a timeout has expired.
If the lock cannot be acquired before the timeout expires, None
is returned.
Otherwise a guard is returned and the lock will be unlocked when the guard is
dropped.
§Example
use std::thread;
use std::time::{Duration, Instant};
use shared_lock::Lock;
let timeout = Duration::from_millis(200);
let lock = Lock::default();
let _guard = lock.lock();
thread::scope(|scope| {
let join_handle = scope.spawn(|| {
let guard = lock.try_lock_for(timeout);
assert!(guard.is_none());
});
join_handle.join().unwrap();
});
Sourcepub fn try_lock_until(&self, instant: Instant) -> Option<Guard<'_>>
pub fn try_lock_until(&self, instant: Instant) -> Option<Guard<'_>>
Attempts to acquire this lock until a timeout is reached.
If the lock cannot be acquired before the timeout expires, None
is returned.
Otherwise a guard is returned and the lock will be unlocked when the guard is
dropped.
§Example
use std::thread;
use std::time::{Duration, Instant};
use shared_lock::Lock;
let timeout = Instant::now() + Duration::from_millis(200);
let lock = Lock::default();
let _guard = lock.lock();
thread::scope(|scope| {
let join_handle = scope.spawn(|| {
let guard = lock.try_lock_until(timeout);
assert!(guard.is_none());
});
join_handle.join().unwrap();
});
Sourcepub fn wrap<T>(&self, value: T) -> Locked<T>
pub fn wrap<T>(&self, value: T) -> Locked<T>
Wraps a value in a Locked
protected by this lock.
This function clones the Lock
which makes it about as expensive as cloning an
Arc
. Note that this is much more expensive than creating an ordinary mutex.
§Example
use shared_lock::Lock;
let lock = Lock::default();
let locked = lock.wrap(5);
let guard = &lock.lock();
assert_eq!(*locked.get(guard), 5);