threadpool_executor/lib.rs
1//!
2//! # Rust Threadpool Executor
3//!
4//! A simple thread pool for running jobs on the worker threads. You can specify the core workers which will live as long as the thread pool , maximum workers which will live with a given keep alive time, and the policy when the jobs submited exceed the maximum size of the workers.
5//!
6//! ## Usage
7//!
8//! Create a fix size thread pool and when the job submited will wait when all workers are busy:
9//!
10//! ```rust
11//!
12//! let pool = threadpool_executor::ThreadPool::new(1);
13//! let mut expectation = pool.execute(|| {"hello, thread pool!"}).unwrap();
14//! assert_eq!(expectation.get_result().unwrap(), "hello, thread pool!");
15//! ```
16//!
17//! You can handle wait the result for a specifid time:
18//!
19//! ```rust
20//! let pool = threadpool_executor::ThreadPool::new(1);
21//! let r = pool.execute(|| {
22//! std::thread::sleep(std::time::Duration::from_secs(10));
23//! });
24//! let res = r.unwrap().get_result_timeout(std::time::Duration::from_secs(3));
25//! assert!(res.is_err());
26//! if let Err(err) = res {
27//! matches!(err.kind(), threadpool_executor::error::ErrorKind::TimeOut);
28//! }
29//! ```
30//!
31//! Use `Builder` to create a thread pool:
32//!
33//! ```rust
34//! let pool = threadpool_executor::threadpool::Builder::new()
35//! .core_pool_size(1)
36//! .maximum_pool_size(3)
37//! .keep_alive_time(std::time::Duration::from_secs(300))
38//! .exeed_limit_policy(threadpool_executor::threadpool::ExceedLimitPolicy::Wait)
39//! .build();
40//! ```
41//!
42//! The workers runs in this thread pool will try to catch the `Panic!` using the `std::panic::catch_unwind` in the functions you submit, if catched, the `get_result` method will give you a `Panic` kind ExecutorError.
43//!
44//! ```rust
45//! let pool = threadpool_executor::ThreadPool::new(1);
46//! let r = pool.execute(|| {
47//! panic!("panic!!!");
48//! });
49//! let res = r.unwrap().get_result();
50//! assert!(res.is_err());
51//! if let Err(err) = res {
52//! matches!(err.kind(), threadpool_executor::error::ErrorKind::Panic);
53//! }
54//! ```
55//!
56//! You can cancel the task when it's waiting in line. The task cannot be cancelled when it's started running.
57//!
58//! ```
59//! let pool = threadpool_executor::ThreadPool::new(1);
60//! pool.execute(|| {
61//! std::thread::sleep(std::time::Duration::from_secs(3));
62//! }).unwrap();
63//! let mut exp = pool.execute(|| {}).unwrap();
64//! exp.cancel();
65//! ```
66
67use crossbeam_channel::{Receiver, Sender};
68use std::{
69 any::Any,
70 collections::HashMap,
71 sync::{
72 atomic::{AtomicBool, AtomicUsize},
73 Arc, Mutex,
74 },
75 thread,
76 time::Duration,
77};
78
79pub mod error;
80pub mod threadpool;
81
82pub struct Expectation<T> {
83 task_cancelled: Arc<AtomicBool>,
84 task_started: Arc<AtomicBool>,
85 task_done: Arc<AtomicBool>,
86 result_receiver: Option<Receiver<Result<T, Box<dyn Any + Send>>>>,
87}
88
89pub struct ThreadPool {
90 current_id: AtomicUsize,
91 workers: Arc<Mutex<HashMap<usize, threadpool::Worker>>>,
92 worker_count: Arc<AtomicUsize>,
93 working_count: Arc<AtomicUsize>,
94 task_sender: Option<Sender<threadpool::Job>>,
95 task_receiver: Receiver<threadpool::Job>,
96 worker_status_sender: Option<Sender<(usize, threadpool::WorkerStatus)>>,
97 m_thread: Option<thread::JoinHandle<()>>,
98 max_size: usize,
99 policy: threadpool::ExceedLimitPolicy,
100 keep_alive_time: Option<Duration>,
101}