Struct Locked

Source
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 if T: 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,

Source

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 Derefs 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);
Source

pub fn into_inner(self) -> T
where 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);
Source

pub fn get_mut(&mut self) -> &mut T

Returns a mutable reference to the contained value.

§Examples
use shared_lock::Lock;

let lock = Lock::default();
let mut locked = lock.wrap(5);
*locked.get_mut() = 6;
assert_eq!(locked.into_inner(), 6);
Source

pub fn data_ptr(&self) -> *const T

Returns a pointer to the underlying value.

§Examples
use shared_lock::Lock;

let lock = Lock::default();
let locked = lock.wrap(5);
// SAFETY: locked hasn't been shared with any other thread.
unsafe {
    assert_eq!(*locked.data_ptr(), 5);
}

Methods from Deref<Target = Lock>§

Source

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 a Guard 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());
Source

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 a Guard 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());
Source

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());
Source

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));
Source

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();
});
Source

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();
Source

pub unsafe fn make_guard_unchecked(&self) -> Guard<'_>

Creates a new Guard without checking if the lock is held.

§Safety
  • The invariant that each Guard owns a ticket must be upheld whenever a Guard is used or dropped.
§Example
use std::mem;
use shared_lock::Lock;

let lock = Lock::default();
mem::forget(lock.lock());
// SAFETY: This recovers the guard we just forgot.
let _guard = unsafe {
    lock.make_guard_unchecked()
};
Source

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();
});
Source

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();
});
Source

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();
});
Source

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);

Trait Implementations§

Source§

impl<T> Debug for Locked<T>
where T: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Deref for Locked<T>
where T: ?Sized,

Source§

type Target = Lock

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<T> Sync for Locked<T>
where T: ?Sized + Send,

Auto Trait Implementations§

§

impl<T> !Freeze for Locked<T>

§

impl<T> !RefUnwindSafe for Locked<T>

§

impl<T> Send for Locked<T>
where T: Send + ?Sized,

§

impl<T> Unpin for Locked<T>
where T: Unpin + ?Sized,

§

impl<T> !UnwindSafe for Locked<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.