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: FA 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: AtomicUsizeThe 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, F> Pool<T, F>
impl<T, F> Pool<T, F>
Sourcepub(super) fn new(create: F) -> Pool<T, F>
pub(super) fn new(create: F) -> Pool<T, F>
Create a new pool. The given closure is used to create values in the pool when necessary.
Sourcepub(super) fn with_capacity(capacity: usize, create: F) -> Pool<T, F>
pub(super) fn with_capacity(capacity: usize, create: F) -> Pool<T, F>
Create a new pool. The given closure is used to create values in the pool when necessary.
The given capacity is used to determine how many cache lines to maintain. Each cache line contains a stack of cached entries.
The capacity must be at least 1. If it’s less than 1, then it is forced to be 1.
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.