lockfree_object_pool/spin_lock_object_pool.rs
1use crate::{
2 spin_lock::SpinLock, spin_lock_owned_reusable::SpinLockOwnedReusable,
3 spin_lock_reusable::SpinLockReusable,
4};
5use std::mem::ManuallyDrop;
6use std::sync::Arc;
7
8/// ObjectPool use a spin lock over vector to secure multithread access to pull.
9///
10/// The spin lock works like [`std::sync::Mutex`] but
11/// * use [`std::sync::atomic::AtomicBool`] for synchro
12/// * active waiting
13///
14/// cf [wikipedia](https://en.wikipedia.org/wiki/Spinlock) for more information.
15///
16/// # Example
17/// ```rust
18/// use lockfree_object_pool::SpinLockObjectPool;
19///
20/// let pool = SpinLockObjectPool::<u32>::new(
21/// || Default::default(),
22/// |v| {
23/// *v = 0;
24/// }
25/// );
26/// let mut item = pool.pull();
27///
28/// *item = 5;
29/// let work = *item * 5;
30/// ```
31pub struct SpinLockObjectPool<T> {
32 objects: SpinLock<Vec<T>>,
33 reset: Box<dyn Fn(&mut T) + Send + Sync>,
34 init: Box<dyn Fn() -> T + Send + Sync>,
35}
36
37impl<T> SpinLockObjectPool<T> {
38 ///
39 /// Create an new [`SpinLockObjectPool`]
40 ///
41 /// # Arguments
42 /// * `init` closure to create new item
43 /// * `reset` closure to reset item before reusage
44 ///
45 /// # Example
46 /// ```rust
47 /// use lockfree_object_pool::SpinLockObjectPool;
48 ///
49 /// let pool = SpinLockObjectPool::<u32>::new(
50 /// || Default::default(),
51 /// |v| {
52 /// *v = 0;
53 /// }
54 /// );
55 /// ```
56 #[inline]
57 pub fn new<R, I>(init: I, reset: R) -> Self
58 where
59 R: Fn(&mut T) + Send + Sync + 'static,
60 I: Fn() -> T + Send + Sync + 'static,
61 {
62 Self {
63 objects: SpinLock::new(Vec::new()),
64 reset: Box::new(reset),
65 init: Box::new(init),
66 }
67 }
68
69 ///
70 /// Create a new element. When the element is dropped, it returns in the pull.
71 ///
72 /// # Example
73 /// ```rust
74 /// use lockfree_object_pool::SpinLockObjectPool;
75 ///
76 /// let pool = SpinLockObjectPool::<u32>::new(
77 /// || Default::default(),
78 /// |v| {
79 /// *v = 0;
80 /// }
81 /// );
82 /// let mut item = pool.pull();
83 /// ```
84 #[inline]
85 pub fn pull(&self) -> SpinLockReusable<T> {
86 SpinLockReusable::new(
87 self,
88 ManuallyDrop::new(self.objects.lock().pop().unwrap_or_else(&self.init)),
89 )
90 }
91
92 ///
93 /// Create a new element. When the element is dropped, it returns in the pull.
94 ///
95 /// # Example
96 /// ```rust
97 /// use lockfree_object_pool::SpinLockObjectPool;
98 /// use std::sync::Arc;
99 ///
100 /// let pool = Arc::new(SpinLockObjectPool::<u32>::new(
101 /// || Default::default(),
102 /// |v| {
103 /// *v = 0;
104 /// }
105 /// ));
106 /// let mut item = pool.pull_owned();
107 /// ```
108 #[inline]
109 pub fn pull_owned(self: &Arc<Self>) -> SpinLockOwnedReusable<T> {
110 SpinLockOwnedReusable::new(
111 self.clone(),
112 ManuallyDrop::new(self.objects.lock().pop().unwrap_or_else(&self.init)),
113 )
114 }
115
116 #[inline]
117 pub(crate) fn attach(&self, mut data: T) {
118 (self.reset)(&mut data);
119 self.objects.lock().push(data);
120 }
121}