terminable_threads/lib.rs
1use std::any::Any;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4use std::sync::atomic::{self, AtomicBool};
5use std::sync::Arc;
6use std::thread::JoinHandle;
7
8/// A basic thread manager that can signal all threads to terminate / finish early
9///
10/// Note that threads will only terminate if the `Arc<AtomicBool>` flag is used
11#[derive(Debug)]
12pub struct TerminableThreads<T, const N: usize> {
13 pub(crate) _threads: [JoinHandle<T>; N],
14 pub(crate) _terminate_flag: Arc<AtomicBool>,
15}
16
17impl<T, const N: usize> TerminableThreads<T, N> {
18 pub fn build() -> (TerminableThreadsBuilder<T, N>, Arc<AtomicBool>) {
19 TerminableThreadsBuilder::new()
20 }
21
22 /// Signal all threads to terminate and cease operation
23 ///
24 /// ## Note
25 ///
26 /// This does not guarantee all threads will terminate, or can be terminated.
27 ///
28 /// Threads will only terminate if the underlying function checks the flag passed to it.s
29 pub fn terminate(&self) {
30 self._terminate_flag
31 .as_ref()
32 .store(true, atomic::Ordering::SeqCst);
33 }
34
35 /// Join all threads, optionally signalling termination
36 ///
37 /// Optional termination signalling is useful because no termination signal
38 /// will let allow a function to run until it has finished naturally, while
39 /// early termination could stop operations earlier than wanted
40 ///
41 /// # Returns
42 ///
43 /// `[Result<T, Error>; N]`
44 ///
45 /// An array of length N containing the results of joining each thread
46 pub fn join(
47 self,
48 signal_terminate: bool,
49 ) -> [Result<T, Box<dyn Any + Send + 'static>>; N] {
50 if signal_terminate {
51 self.terminate();
52 }
53
54 self._threads.map(JoinHandle::join)
55 }
56}
57
58/// Basic builder for a terminable thread object
59///
60/// The builder is necessary to provide the termination flag (`Arc<AtomicBool>`)
61/// for threads, that are later provided to the builder, to use.
62#[derive(Debug)]
63pub struct TerminableThreadsBuilder<T, const N: usize> {
64 terminate_flag: Arc<AtomicBool>,
65 _marker: PhantomData<T>,
66}
67
68impl<T, const N: usize> TerminableThreadsBuilder<T, N> {
69 /// Create a new `TeminableThreadBuilder`
70 pub fn new() -> (Self, Arc<AtomicBool>) {
71 let flag = Arc::new(AtomicBool::new(false));
72
73 (
74 Self {
75 terminate_flag: Arc::clone(&flag),
76 _marker: PhantomData,
77 },
78 flag,
79 )
80 }
81
82 /// Transform the builder into a `TerminableThreads<T, N>` struct with the specified threads
83 pub fn build_with_threads(self, threads: [JoinHandle<T>; N]) -> TerminableThreads<T, N> {
84 TerminableThreads {
85 _terminate_flag: self.terminate_flag,
86 _threads: threads,
87 }
88 }
89}