pub struct PMutex<T, A: MemPool> { /* private fields */ }
Expand description

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 corundum::default::*;
use std::sync::Mutex;
 
type P = Allocator;
 
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 corundum::default::*;
 
type P = Allocator;
 
// PMutex<T> = corundum::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

Creates a new Mutex

Examples
 
Heap::transaction(|j| {
    let p = Parc::new(PMutex::new(10), j);
}).unwrap();

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 corundum::default::*;
use std::thread;
 
type P = Allocator;
 
let obj = P::open::<Parc<PMutex<i32>>>("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::demote(&obj);
thread::spawn(move || {
    transaction(move |j| {
        if let Some(obj) = obj.promote(j) {
            *obj.lock(j) += 1;
        }
    }).unwrap();
}).join().expect("thread::spawn failed");

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 corundum::default::*;
use std::thread;
 
type P = Allocator;
 
let obj = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap();

let a = Parc::demote(&obj);
thread::spawn(move || {
    transaction(|j| {
        if let Some(obj) = a.promote(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

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.