thread_manager/looper.rs
1use std::cell::Cell;
2use std::sync::atomic::AtomicBool;
3use std::sync::Arc;
4use std::thread;
5
6use crate::order::LOAD_ORDER;
7use crate::order::STORE_ORDER;
8
9/// The `ThreadLooper` struct is designed for managing a looping background thread.
10///
11/// This struct provides functionality to start, manage, and terminate a looping background thread.
12/// It is useful for tasks that need to run continuously in the background until explicitly stopped.
13///
14/// # Fields
15/// - `status`: An `Arc<AtomicBool>` indicating whether the looper is active.
16/// - `thread`: A `Cell` containing an `Option<thread::JoinHandle<()>>` for the background thread.
17/// - `termination`: An `Arc<AtomicBool>` indicating whether the looper should be terminated.
18pub struct ThreadLooper {
19 status: Arc<AtomicBool>,
20 thread: Cell<Option<thread::JoinHandle<()>>>,
21 termination: Arc<AtomicBool>,
22}
23
24impl ThreadLooper {
25 /// Creates a new instance of `ThreadLooper`.
26 ///
27 /// Initializes the status and termination flags to `false` and sets the thread handle to `None`.
28 ///
29 /// # Returns
30 /// A new instance of `ThreadLooper`.
31 pub fn new() -> Self {
32 let status: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
33 let thread: Cell<Option<thread::JoinHandle<()>>> = Cell::new(None);
34 let termination: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
35
36 Self {
37 status,
38 thread,
39 termination,
40 }
41 }
42
43 /// Checks if the looper is currently active.
44 pub fn is_active(&self) -> bool {
45 self.status.load(LOAD_ORDER)
46 }
47
48 /// Starts the looper with the given function.
49 ///
50 /// If the looper is not already active, this method will start the background thread and run the provided function in a loop.
51 ///
52 /// # Type Parameters
53 /// - `F`: The type of the function to execute in the loop.
54 ///
55 /// # Arguments
56 /// - `function`: The function to be executed in the background thread.
57 pub fn start<F>(&self, function: F)
58 where
59 F: Fn() -> () + Send + 'static,
60 {
61 if !self.is_active() {
62 self.status.store(true, STORE_ORDER);
63 self.termination.store(false, STORE_ORDER);
64
65 let thread: thread::JoinHandle<()> = thread::spawn(self.create(function));
66 self.thread.set(Some(thread));
67 }
68 }
69
70 /// Terminates the background thread.
71 ///
72 /// If the background thread is running, this method will signal it to stop and join the thread, effectively waiting for it to finish execution.
73 pub fn terminate(&self) {
74 self.termination.store(true, STORE_ORDER);
75 if let Some(thread) = self.thread.take() {
76 let _ = thread.join();
77 }
78 }
79}
80
81impl ThreadLooper {
82 fn create<F>(&self, function: F) -> impl Fn()
83 where
84 F: Fn() -> () + Send + 'static,
85 {
86 let status: Arc<AtomicBool> = self.status.clone();
87 let termination: Arc<AtomicBool> = self.termination.clone();
88
89 let worker = move || {
90 while !termination.load(LOAD_ORDER) {
91 function();
92 }
93 status.store(false, STORE_ORDER);
94 termination.store(false, STORE_ORDER);
95 };
96 worker
97 }
98}