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 Copy
ing
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>
impl<T> Mutex<T>
sourcepub fn get_mut(&mut self) -> &mut T
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.
sourcepub fn into_inner(self) -> T
pub fn into_inner(self) -> T
Unwraps the contained value, consuming the mutex.
sourcepub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T
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>>
impl<T> Mutex<RefCell<T>>
sourcepub fn replace<'cs>(&'cs self, cs: CriticalSection<'cs>, t: T) -> T
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.
sourcepub fn replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> Twhere
F: FnOnce(&mut T) -> T,
pub fn replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> Twhere 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.
sourcepub fn borrow_ref<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, T>
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.
sourcepub fn borrow_ref_mut<'cs>(
&'cs self,
cs: CriticalSection<'cs>
) -> RefMut<'cs, T>
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>>
impl<T: Default> Mutex<RefCell<T>>
sourcepub fn take<'cs>(&'cs self, cs: CriticalSection<'cs>) -> T
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.