[][src]Struct crndm::sync::Mutex

pub struct Mutex<T, A: MemPool> { /* fields omitted */ }

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]

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]

impl<T, A> Unpin for Mutex<T, A> where
    A: Unpin,
    T: Unpin
[src]

impl<T, A> VSafe for Mutex<T, A> where
    A: VSafe,
    T: VSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,