bp3d_threads/thread_pool/unscoped.rs
1// Copyright (c) 2021, BlockProject 3D
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification,
6// are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of BlockProject 3D nor the names of its contributors
14// may be used to endorse or promote products derived from this software
15// without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29use crate::thread_pool::core::ThreadManager;
30use crate::Join;
31use std::thread::JoinHandle;
32
33impl Join for JoinHandle<()> {
34 fn join(self) -> std::thread::Result<()> {
35 self.join()
36 }
37}
38
39/// Represents an UnscopedThreadManager (using low level std::thread::spawn).
40pub struct UnscopedThreadManager();
41
42impl Default for UnscopedThreadManager {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl UnscopedThreadManager {
49 /// Creates new UnscopedThreadManager.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use bp3d_threads::ThreadPool;
55 /// use bp3d_threads::UnscopedThreadManager;
56 /// let manager = UnscopedThreadManager::new();
57 /// let mut pool: ThreadPool<UnscopedThreadManager, i32> = ThreadPool::new(4);
58 /// assert!(pool.is_idle());
59 /// pool.send(&manager, |_| 12);
60 /// assert!(!pool.is_idle());
61 /// pool.wait().unwrap();
62 /// assert!(pool.is_idle());
63 /// ```
64 pub fn new() -> Self {
65 Self()
66 }
67}
68
69impl ThreadManager<'static> for UnscopedThreadManager {
70 type Handle = JoinHandle<()>;
71
72 fn spawn_thread<F: FnOnce() + Send + 'static>(&self, func: F) -> Self::Handle {
73 std::thread::spawn(func)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use crate::thread_pool::{ThreadPool, UnscopedThreadManager};
80
81 fn fibonacci_recursive(n: usize) -> usize {
82 if n == 0 {
83 0
84 } else if n == 1 {
85 1
86 } else {
87 fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
88 }
89 }
90
91 #[test]
92 fn basic() {
93 const N: usize = 50;
94 let manager = UnscopedThreadManager::new();
95 let mut pool: ThreadPool<UnscopedThreadManager, usize> = ThreadPool::new(4);
96 for _ in 0..N {
97 pool.send(&manager, |_| fibonacci_recursive(20));
98 }
99 assert!(!pool.is_idle());
100 pool.wait().unwrap();
101 assert!(pool.is_idle());
102 let mut tasks = 0;
103 while let Some(event) = pool.poll() {
104 assert_eq!(event, 6765);
105 tasks += 1;
106 }
107 assert_eq!(tasks, N);
108 }
109
110 #[test]
111 fn reduce() {
112 const N: usize = 50;
113 let manager = UnscopedThreadManager::new();
114 let mut pool: ThreadPool<UnscopedThreadManager, usize> = ThreadPool::new(4);
115 for _ in 0..N {
116 pool.send(&manager, |_| fibonacci_recursive(20));
117 }
118 assert!(!pool.is_idle());
119 let tasks = pool.reduce().count();
120 assert_eq!(tasks, N);
121 assert!(pool.is_idle());
122 }
123}