Struct critical_section::Mutex

source ·
pub struct Mutex<T> { /* private fields */ }
Expand description

A mutex based on critical sections.

§Example


static FOO: Mutex<Cell<i32>> = Mutex::new(Cell::new(42));

fn main() {
    critical_section::with(|cs| {
        FOO.borrow(cs).set(43);
    });
}

fn interrupt_handler() {
    let _x = critical_section::with(|cs| FOO.borrow(cs).get());
}

§Design

std::sync::Mutex has two purposes. It converts types that are [Send] but not [Sync] into types that are both; and it provides interior mutability. critical_section::Mutex, on the other hand, only adds Sync. It does not provide interior mutability.

This was a conscious design choice. It is possible to create multiple CriticalSection tokens, either by nesting critical sections or Copying an existing token. As a result, it would not be sound for Mutex::borrow to return &mut T, because there would be nothing to prevent calling borrow multiple times to create aliased &mut T references.

The solution is to include a runtime check to ensure that each resource is borrowed only once. This is what std::sync::Mutex does. However, this is a runtime cost that may not be required in all circumstances. For instance, Mutex<Cell<T>> never needs to create &mut T or equivalent.

If &mut T is needed, the simplest solution is to use Mutex<RefCell<T>>, which is the closest analogy to std::sync::Mutex. [RefCell] inserts the exact runtime check necessary to guarantee that the &mut T reference is unique.

To reduce verbosity when using Mutex<RefCell<T>>, we reimplement some of RefCell’s methods on it directly.


static FOO: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(42));

fn main() {
    critical_section::with(|cs| {
        // Instead of calling this
        let _ = FOO.borrow(cs).take();
        // Call this
        let _ = FOO.take(cs);
        // `RefCell::borrow` and `RefCell::borrow_mut` are renamed to
        // `borrow_ref` and `borrow_ref_mut` to avoid name collisions
        let _: &mut i32 = &mut *FOO.borrow_ref_mut(cs);
    })
}

Implementations§

source§

impl<T> Mutex<T>

source

pub const fn new(value: T) -> Self

Creates a new mutex.

source

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

Gets a mutable reference to the contained value when the mutex is already uniquely borrowed.

This does not require locking or a critical section since it takes &mut self, which guarantees unique ownership already. Care must be taken when using this method to unsafely access static mut variables, appropriate fences must be used to prevent unwanted optimizations.

source

pub fn into_inner(self) -> T

Unwraps the contained value, consuming the mutex.

source

pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T

Borrows the data for the duration of the critical section.

source§

impl<T> Mutex<RefCell<T>>

source

pub fn replace<'cs>(&'cs self, cs: CriticalSection<'cs>, t: T) -> T

Borrow the data and call [RefCell::replace]

This is equivalent to self.borrow(cs).replace(t)

§Panics

This call could panic. See the documentation for [RefCell::replace] for more details.

source

pub fn replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> T
where F: FnOnce(&mut T) -> T,

Borrow the data and call [RefCell::replace_with]

This is equivalent to self.borrow(cs).replace_with(f)

§Panics

This call could panic. See the documentation for [RefCell::replace_with] for more details.

source

pub fn borrow_ref<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, T>

Borrow the data and call [RefCell::borrow]

This is equivalent to self.borrow(cs).borrow()

§Panics

This call could panic. See the documentation for [RefCell::borrow] for more details.

source

pub fn borrow_ref_mut<'cs>( &'cs self, cs: CriticalSection<'cs>, ) -> RefMut<'cs, T>

Borrow the data and call [RefCell::borrow_mut]

This is equivalent to self.borrow(cs).borrow_mut()

§Panics

This call could panic. See the documentation for [RefCell::borrow_mut] for more details.

source§

impl<T: Default> Mutex<RefCell<T>>

source

pub fn take<'cs>(&'cs self, cs: CriticalSection<'cs>) -> T

Borrow the data and call [RefCell::take]

This is equivalent to self.borrow(cs).take()

§Panics

This call could panic. See the documentation for [RefCell::take] for more details.

Trait Implementations§

source§

impl<T: Debug> Debug for Mutex<T>

source§

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

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

impl<T> Sync for Mutex<T>
where T: Send,

Auto Trait Implementations§

§

impl<T> !Freeze for Mutex<T>

§

impl<T> !RefUnwindSafe for Mutex<T>

§

impl<T> Send for Mutex<T>
where T: Send,

§

impl<T> Unpin for Mutex<T>
where T: Unpin,

§

impl<T> UnwindSafe for Mutex<T>
where T: UnwindSafe,

Blanket Implementations§

§

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

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

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

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

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

§

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

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

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

§

fn into(self) -> U

Calls U::from(self).

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

§

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

§

type Error = Infallible

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

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

Performs the conversion.
§

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

§

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

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

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

Performs the conversion.