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}