[−][src]Struct crndm::sync::Parc
A thread-safe reference-counting persistent pointer. 'Parc' stands for 'Persistent Atomically Reference Counted'.
The main aspect of Parc<T>
is that its atomic counters are also
transactional to provide failure atomicity which means that functions
pclone
, downgrade
, and upgrade
require a Journal
to operate.
In other words, you need to wrap them in a transaction
. The counters are
atomic, so it is safe to share it in multiple threads.
Unlike Arc
, Parc
does not implement Send
to prevent memory leak.
The reason is that if a Parc
is created in a transaction without being
reachable from the root object, and moves to a thread, due to being RAII,
its drop function gets called in the other thread outside the original
transaction. Therefore, it destroys allocation consistency and leaves the
Parc
unreachable in the memory if a crash happens between the original
transaction is done and the drop function is called.
To allow sharing, Parc
provides a safe mechanism to cross the thread
boundaries. When you need to share it, you can obtain a VWeak
object by calling volatile()
function. The VWeak
object is both
Sync
and Send
and acts like a volatile reference. Calling
VWeak
::
upgrade()
gives access to data by creating a new reference
of type Parc
inside the other thread, if the referent is still available.
Calling volatile()
is dynamically prohibited to be inside a transaction.
Therefore, the Parc
should be already reachable from the root object and
packed outside a transaction.
Examples
use crndm::default::*; use std::thread; type P = BuddyAlloc; let p = P::open::<Parc<i32>>("foo.pool", O_CF).unwrap(); let v = p.volatile(); let mut threads = vec![]; for i in 0..10 { let p = v.clone(); threads.push(thread::spawn(move || { transaction(|j| { if let Some(p) = p.upgrade(j) { println!("access {} from thread {}", *p, i); } }).unwrap(); })); } for t in threads { t.join().unwrap(); }
Mutability
Parc
doesn't provide mutable reference to the inner value. To allow
interior mutability, you may use Parc<
Mutex
<T,P>,P>
(or in short,
Parc<
PMutex
<T>>
using aliased types).
use crndm::default::*; use std::thread; type P = BuddyAlloc; let p = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap(); let v = p.volatile(); let mut threads = vec![]; for i in 0..10 { let p = v.clone(); threads.push(thread::spawn(move || { transaction(|j| { if let Some(p) = p.upgrade(j) { let mut p = p.lock(j); *p += 1; println!("thread {} makes it {}", i, *p); } }).unwrap(); })); } for t in threads { t.join().unwrap(); } let res = transaction(|j| { *p.lock(j) }).unwrap(); assert_eq!(res, 10);
Implementations
impl<T: PSafe, A: MemPool> Parc<T, A>
[src]
pub fn new(value: T, journal: &Journal<A>) -> Parc<T, A>
[src]
Constructs a new Parc<T>
.
Examples
use crndm::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); }).unwrap();
pub fn new_uninit(journal: &Journal<A>) -> Parc<MaybeUninit<T>, A>
[src]
Constructs a new Parc
with uninitialized contents.
Examples
use crndm::alloc::*; use crndm::sync::Parc; crndm::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5) }).unwrap();
pub fn new_zeroed(journal: &Journal<A>) -> Parc<MaybeUninit<T>, A>
[src]
Constructs a new Parc
with uninitialized contents, with the memory
being filled with 0
bytes.
See MaybeUninit::zeroed
for examples of correct and incorrect usage of
this method.
Examples
use crndm::alloc::*; use crndm::sync::Parc; Heap::transaction(|j| { let zero = Parc::<u32,Heap>::new_zeroed(j); let zero = unsafe { zero.assume_init() }; assert_eq!(*zero, 0) }).unwrap();
impl<T: PSafe, A: MemPool> Parc<MaybeUninit<T>, A>
[src]
pub unsafe fn assume_init(self) -> Parc<T, A>
[src]
Converts to Parc<T>
.
Safety
As with MaybeUninit::assume_init
,
it is up to the caller to guarantee that the inner value
really is in an initialized state.
Calling this when the content is not yet fully initialized
causes immediate undefined behavior.
Examples
use crndm::alloc::*; use crndm::sync::Parc; crndm::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5); }).unwrap();
impl<T: PSafe, A: MemPool> Parc<MaybeUninit<T>, A>
[src]
pub fn get_mut(this: &mut Self) -> Option<&mut MaybeUninit<T>>
[src]
Returns a mutable reference into the given Parc
, if there are
no other Parc
or Weak
pointers to the same allocation.
Returns None
otherwise, because it is not safe to mutate a shared
value. It only works for Parc<MaybeUninit<T>>
to be able to defer the
initialization.
Examples
use crndm::alloc::*; use crndm::sync::Parc; crndm::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut(&mut five).unwrap().as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5) }).unwrap();
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut MaybeUninit<T>
[src]
Returns a mutable reference into the given Parc
, without any check.
It only works for Parc<MaybeUninit<T>>
to be able to defer the
initialization.
Safety
Any other Parc
or Weak
pointers to the same allocation must not
be dereferenced for the duration of the returned borrow. This is
trivially the case if no such pointers exist, for example immediately
after Parc::new
.
Examples
use crndm::alloc::*; use crndm::sync::Parc; crndm::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5); }).unwrap();
impl<T: PSafe + ?Sized, A: MemPool> Parc<T, A>
[src]
pub fn downgrade(this: &Self, _journal: &Journal<A>) -> Weak<T, A>
[src]
Creates a new Weak
pointer to this allocation.
The Weak
pointer can be upgrade
d later in a transaction.
Examples
use crndm::alloc::*; use crndm::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); let _weak_five = Parc::downgrade(&five, j); }).unwrap()
pub fn volatile(&self) -> VWeak<T, A>
[src]
Creates a new sharable VWeak
pointer to this
allocation.
Errors
This function requires the allocation to be reachable from the persistent root. Therefore, it panics if it gets called inside a transaction.
Examples
use crndm::default::*; type P = BuddyAlloc; let obj = P::open::<Parc<i32>>("foo.pool", O_CF).unwrap(); let v = obj.volatile(); assert_eq!(Parc::strong_count(&obj), 1); P::transaction(|j| { if let Some(obj) = v.upgrade(j) { assert_eq!(Parc::strong_count(&obj), 2); } }).unwrap(); assert_eq!(Parc::strong_count(&obj), 1);
pub fn weak_count(this: &Self) -> usize
[src]
Gets the number of Weak
pointers to this allocation.
Examples
use crndm::alloc::*; use crndm::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); let _weak_five = Parc::downgrade(&five, j); assert_eq!(1, Parc::weak_count(&five)); }).unwrap()
pub fn strong_count(this: &Self) -> usize
[src]
Gets the number of Strong
pointers to this allocation.
Examples
use crndm::alloc::*; use crndm::sync::Parc; use crndm::clone::PClone; Heap::transaction(|j| { let five = Parc::new(5, j); let _also_five = Parc::pclone(&five, j); assert_eq!(2, Parc::strong_count(&five)); }).unwrap();
pub fn ptr_eq(this: &Self, other: &Self) -> bool
[src]
Returns true
if the two Parc
s point to the same allocation
(in a vein similar to std::ptr::eq
).
Examples
use crndm::alloc::*; use crndm::sync::Parc; use crndm::clone::PClone; Heap::transaction(|j| { let five = Parc::new(5, j); let same_five = Parc::pclone(&five, j); let other_five = Parc::new(5, j); assert!(Parc::ptr_eq(&five, &same_five)); assert!(!Parc::ptr_eq(&five, &other_five)); }).unwrap();
Trait Implementations
impl<T: PSafe + ?Sized, A: MemPool> AsRef<T> for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Borrow<T> for Parc<T, A>
[src]
impl<T: Debug + PSafe, A: MemPool> Debug for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Deref for Parc<T, A>
[src]
impl<T: Display + PSafe, A: MemPool> Display for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Drop for Parc<T, A>
[src]
pub fn drop(&mut self)
[src]
Drops the Parc
safely
This will decrement the strong reference count. If the strong reference
count reaches zero then the only other references (if any) are
Weak
, so we drop
the inner value on commit using a DropOnCommit
log.
Examples
use crndm::alloc::*; use crndm::sync::Parc; use crndm::clone::PClone; struct Foo; impl Drop for Foo { fn drop(&mut self) { println!("dropped!"); } } Heap::transaction(|j| { let foo = Parc::new(Foo, j); let foo2 = Parc::pclone(&foo, j); drop(foo); // Doesn't print anything drop(foo2); // Prints "dropped!" }).unwrap();
impl<T: Eq + PSafe + ?Sized, A: MemPool> Eq for Parc<T, A>
[src]
impl<T: Hash + PSafe, A: MemPool> Hash for Parc<T, A>
[src]
pub fn hash<H: Hasher>(&self, state: &mut H)
[src]
pub fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl<T: Ord + PSafe + ?Sized, A: MemPool> Ord for Parc<T, A>
[src]
pub fn cmp(&self, other: &Parc<T, A>) -> Ordering
[src]
#[must_use]pub fn max(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn min(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn clamp(self, min: Self, max: Self) -> Self
1.50.0[src]
impl<T: PSafe + ?Sized, A: MemPool> PClone<A> for Parc<T, A>
[src]
pub fn pclone(&self, _journal: &Journal<A>) -> Parc<T, A>
[src]
pub fn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
[src]
impl<T: PartialEq + PSafe + ?Sized, A: MemPool> PartialEq<Parc<T, A>> for Parc<T, A>
[src]
pub fn eq(&self, other: &Parc<T, A>) -> bool
[src]
#[must_use]pub fn ne(&self, other: &Rhs) -> bool
1.0.0[src]
impl<T: PartialOrd + PSafe + ?Sized, A: MemPool> PartialOrd<Parc<T, A>> for Parc<T, A>
[src]
pub fn partial_cmp(&self, other: &Parc<T, A>) -> Option<Ordering>
[src]
pub fn lt(&self, other: &Parc<T, A>) -> bool
[src]
pub fn le(&self, other: &Parc<T, A>) -> bool
[src]
pub fn gt(&self, other: &Parc<T, A>) -> bool
[src]
pub fn ge(&self, other: &Parc<T, A>) -> bool
[src]
impl<T: PSafe, A: MemPool> PmemUsage for Parc<T, A>
[src]
impl<T: PSafe + PmemUsage + ?Sized, A: MemPool> PmemUsage for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Pointer for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> RefUnwindSafe for Parc<T, A>
[src]
impl<T: RootObj<A> + PSafe, A: MemPool> RootObj<A> for Parc<T, A>
[src]
impl<T: Default + PSafe + ?Sized, A: MemPool> RootObj<A> for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !Send for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> TxInSafe for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !TxOutSafe for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Unpin for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> UnwindSafe for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !VSafe for Parc<T, A>
[src]
Auto Trait Implementations
impl<T: ?Sized, A> LooseTxInUnsafe for Parc<T, A> where
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
[src]
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
impl<T: ?Sized, A> PSafe for Parc<T, A>
[src]
impl<T, A> !Sync for Parc<T, A>
[src]
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> ToString for T where
T: Display + ?Sized,
[src]
T: Display + ?Sized,
impl<T, A> ToString<A> for T where
A: MemPool,
T: Display + ?Sized,
[src]
A: MemPool,
T: Display + ?Sized,
pub default fn to_pstring(&Self, &Journal<A>) -> String<A>
[src]
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>,