[−][src]Struct crndm::sync::Mutex
A transaction-wide recursive mutual exclusion primitive useful for protecting shared data while transaction is open. Further locking in the same thread is non-blocking. Any access to data is serialized. Borrow rules are checked dynamically to prevent multiple mutable dereferencing.
This mutex will block threads/transactions waiting for the lock to become
available. The difference between Mutex
and std
::
sync
::
Mutex
is that it will hold the lock until the transaction commits. For example,
consider the following code snippet in which a shared object is protected
with std
::
sync
::
Mutex
. In this case, data might be lost.
use crndm::default::*;
use std::sync::Mutex;
type P = BuddyAlloc;
let obj = P::open::<Parc<Mutex<i32>>>("foo.pool", O_CF).unwrap();
// ^ std::sync::Mutex is not PSafe
transaction(|j| {
{
let obj = obj.lock().unwrap();
// Some statements ...
} // <-- release the lock here
// Another thread can work with obj
{
let obj = obj.lock().unwrap();
// Some statements ...
} // <-- release the lock here
// A crash may happen here after another thread has used updated data
// which leads to an inconsistent state
});
The safest way to have a shared object protected from both data-race and
data-loss is to wrap it with a transaction-wide Mutex
as in the following
example:
use crndm::default::*; type P = BuddyAlloc; // PMutex<T> = crndm::sync::Mutex<T,P> let obj = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap(); transaction(|j| { { let obj = obj.lock(j); // Some statements ... } // data is still locked. { let obj = obj.lock(j); // <-- does not block the current thread // Some statements ... } }); // <-- release the lock here after committing or rolling back the transaction
Implementations
impl<T, A: MemPool> Mutex<T, A>
[src]
pub fn new(data: T, _journal: &Journal<A>) -> Mutex<T, A>
[src]
Creates a new Mutex
Examples
use crndm::sync::{Parc,Mutex}; Heap::transaction(|j| { let p = Parc::new(Mutex::new(10, j), j); }).unwrap();
impl<T, A: MemPool> Mutex<T, A>
[src]
pub fn lock<'a>(&'a self, journal: &'a Journal<A>) -> MutexGuard<'a, T, A>
[src]
Acquires a mutex, blocking the current thread until it is able to do so.
This function will block the local thread until it is available to
acquire the mutex. Upon returning, the thread is the only thread with
the lock held. An RAII guard is returned to keep track of borrowing
data. It creates an UnlockOnCommit
log to unlock the mutex when
transaction is done.
If the local thread already holds the lock, lock()
does not block it.
The mutex remains locked until the transaction is committed.
Alternatively, PMutex
can be used as a compact form of Mutex
.
Examples
use crndm::default::*; use crndm::sync::{Parc,Mutex}; use std::thread; type P = BuddyAlloc; let obj = P::open::<Parc<Mutex<i32,P>,P>>("foo.pool", O_CF).unwrap(); // Using short forms in the pool module, there is no need to specify the // pool type, as follows: // let obj = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap(); let obj = Parc::volatile(&obj); thread::spawn(move || { transaction(move |j| { if let Some(obj) = obj.upgrade(j) { *obj.lock(j) += 1; } }).unwrap(); }).join().expect("thread::spawn failed");
pub fn try_lock<'a>(
&'a self,
journal: &'a Journal<A>
) -> TryLockResult<MutexGuard<'a, T, A>>
[src]
&'a self,
journal: &'a Journal<A>
) -> TryLockResult<MutexGuard<'a, T, A>>
Attempts to acquire this lock.
If the lock could not be acquired at this time, then Err
is returned.
Otherwise, an RAII guard is returned. The lock will be unlocked when the
owner transaction ends.
This function does not block.
Errors
If another user of this mutex holds a guard, then this call will return failure if the mutex would otherwise be acquired.
Examples
use crndm::default::*; use std::thread; type P = BuddyAlloc; let obj = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap(); let a = Parc::volatile(&obj); thread::spawn(move || { transaction(|j| { if let Some(obj) = a.upgrade(j) { let mut lock = obj.try_lock(j); if let Ok(ref mut mutex) = lock { **mutex = 10; } else { println!("try_lock failed"); } } }).unwrap(); }).join().expect("thread::spawn failed"); transaction(|j| { assert_eq!(*obj.lock(j), 10); }).unwrap();
Trait Implementations
impl<T: Debug, A: MemPool> Debug for Mutex<T, A>
[src]
impl<T, A: MemPool> PSafe for Mutex<T, A>
[src]
impl<T, A: MemPool> RefUnwindSafe for Mutex<T, A>
[src]
impl<T: RootObj<A>, A: MemPool> RootObj<A> for Mutex<T, A>
[src]
impl<T: Send, A: MemPool> Send for Mutex<T, A>
[src]
impl<T: Send, A: MemPool> Sync for Mutex<T, A>
[src]
impl<T, A: MemPool> TxInSafe for Mutex<T, A>
[src]
impl<T: ?Sized, A: MemPool> !TxOutSafe for Mutex<T, A>
[src]
impl<T, A: MemPool> UnwindSafe for Mutex<T, A>
[src]
Auto Trait Implementations
impl<T, A> LooseTxInUnsafe for Mutex<T, A> where
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
[src]
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
impl<T, A> Unpin for Mutex<T, A> where
A: Unpin,
T: Unpin,
[src]
A: Unpin,
T: Unpin,
impl<T, A> VSafe for Mutex<T, A> where
A: VSafe,
T: VSafe,
[src]
A: VSafe,
T: VSafe,
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
V: MultiLane<T>,