mod pool;
mod queue;
use std::{sync::OnceLock, thread, time::Duration};
use parking_lot::Mutex;
use queue::*;
pub use pool::*;
static POOL: OnceLock<ThreadPool> = OnceLock::new();
static INIT_LOCK: Mutex<()> = Mutex::new(());
#[allow(clippy::result_unit_err)]
pub fn init(name_pattern: &str, num_threads: usize) -> Result<(), ()> {
let _guard = INIT_LOCK.lock();
if POOL.get().is_some() {
return Err(());
}
POOL.set(ThreadPool::new(name_pattern, num_threads))
.map_err(|_| ())
}
pub fn loop_and_sleep_until<F, P>(f: F, ok: P, sleep_for: Duration)
where
F: FnMut() + Send + 'static,
P: FnMut() -> bool + Send + 'static,
{
submit(move || {
let mut f = f;
let mut ok = ok;
loop {
f();
if ok() {
break;
}
thread::sleep(sleep_for);
}
});
}
pub fn submit<F: FnOnce() + Send + 'static>(task: F) {
global_pool().submit(task);
}
fn global_pool() -> &'static ThreadPool {
if let Some(pool) = POOL.get() {
return pool;
}
let _guard = INIT_LOCK.lock();
if let Some(pool) = POOL.get() {
return pool;
}
let result = POOL.set(ThreadPool::new("ncd-dsptch", 4));
debug_assert!(result.is_ok());
POOL.get().expect("global pool was just initialized")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn repeated_init_does_not_construct_another_pool() {
assert!(init("global", 1).is_ok());
assert!(init("not\0constructed", 1).is_err());
}
}