pub(super) struct Pool<T, F> {
create: F,
stacks: Vec<CacheLine<Mutex<Vec<Box<T>>>>>,
owner: AtomicUsize,
owner_val: UnsafeCell<Option<T>>,
}
Expand description
A thread safe pool utilizing std-only features.
The main difference between this and the simplistic alloc-only pool is the use of std::sync::Mutex and an “owner thread” optimization that makes accesses by the owner of a pool faster than all other threads. This makes the common case of running a regex within a single thread faster by avoiding mutex unlocking.
Fields§
§create: F
A function to create more T values when stack is empty and a caller has requested a T.
stacks: Vec<CacheLine<Mutex<Vec<Box<T>>>>>
Multiple stacks of T values to hand out. These are used when a Pool is accessed by a thread that didn’t create it.
Conceptually this is Mutex<Vec<Box<T>>>
, but sharded out to make
it scale better under high contention work-loads. We index into
this sequence via thread_id % stacks.len()
.
owner: AtomicUsize
The ID of the thread that owns this pool. The owner is the thread that makes the first call to ‘get’. When the owner calls ‘get’, it gets ‘owner_val’ directly instead of returning a T from ‘stack’. See comments elsewhere for details, but this is intended to be an optimization for the common case that makes getting a T faster.
It is initialized to a value of zero (an impossible thread ID) as a sentinel to indicate that it is unowned.
owner_val: UnsafeCell<Option<T>>
A value to return when the caller is in the same thread that
first called Pool::get
.
This is set to None when a Pool is first created, and set to Some once the first thread calls Pool::get.
Implementations§
source§impl<T: Send, F: Fn() -> T> Pool<T, F>
impl<T: Send, F: Fn() -> T> Pool<T, F>
sourcepub(super) fn get(&self) -> PoolGuard<'_, T, F>
pub(super) fn get(&self) -> PoolGuard<'_, T, F>
Get a value from the pool. This may block if another thread is also attempting to retrieve a value from the pool.
sourcefn get_slow(&self, caller: usize, owner: usize) -> PoolGuard<'_, T, F>
fn get_slow(&self, caller: usize, owner: usize) -> PoolGuard<'_, T, F>
This is the “slow” version that goes through a mutex to pop an allocated value off a stack to return to the caller. (Or, if the stack is empty, a new value is created.)
If the pool has no owner, then this will set the owner.
sourcefn put_value(&self, value: Box<T>)
fn put_value(&self, value: Box<T>)
Puts a value back into the pool. Callers don’t need to call this. Once the guard that’s returned by ‘get’ is dropped, it is put back into the pool automatically.
sourcefn guard_owned(&self, caller: usize) -> PoolGuard<'_, T, F>
fn guard_owned(&self, caller: usize) -> PoolGuard<'_, T, F>
Create a guard that represents the special owned T.
sourcefn guard_stack(&self, value: Box<T>) -> PoolGuard<'_, T, F>
fn guard_stack(&self, value: Box<T>) -> PoolGuard<'_, T, F>
Create a guard that contains a value from the pool’s stack.
sourcefn guard_stack_transient(&self, value: Box<T>) -> PoolGuard<'_, T, F>
fn guard_stack_transient(&self, value: Box<T>) -> PoolGuard<'_, T, F>
Create a guard that contains a value from the pool’s stack with an instruction to throw away the value instead of putting it back into the pool.