windows_threading/
pool.rs

1use super::*;
2
3/// A `Pool` object represents a private thread pool with its own thread limits.
4///
5/// This is in contrast to the default, or shared, thread pool used by the crate's `submit` function
6/// as well as other code within the same process.
7pub struct Pool(Box<TP_CALLBACK_ENVIRON_V3>);
8
9impl Pool {
10    /// Creates a new `Pool` object.
11    pub fn new() -> Self {
12        let mut e = TP_CALLBACK_ENVIRON_V3 {
13            Version: 3,
14            CallbackPriority: TP_CALLBACK_PRIORITY_NORMAL,
15            Size: core::mem::size_of::<TP_CALLBACK_ENVIRON_V3>() as u32,
16            ..Default::default()
17        };
18
19        unsafe {
20            e.Pool = check(CreateThreadpool(core::ptr::null()));
21            e.CleanupGroup = check(CreateThreadpoolCleanupGroup());
22        }
23
24        // The `TP_CALLBACK_ENVIRON_V3` is boxed to ensure its memory address remains stable for the life of the `Pool` object.
25        Self(Box::new(e))
26    }
27
28    /// Sets the thread limits for the `Pool` object.
29    pub fn set_thread_limits(&self, min: u32, max: u32) {
30        unsafe {
31            check(SetThreadpoolThreadMinimum(self.0.Pool, min));
32            SetThreadpoolThreadMaximum(self.0.Pool, max);
33        }
34    }
35
36    /// Submits the closure to run on the `Pool`.
37    ///
38    /// The closure cannot outlive the `Pool` on which it runs.
39    pub fn submit<'a, F: FnOnce() + Send + 'a>(&'a self, f: F) {
40        // This is safe because the lifetime of the closure is bounded by the `Pool`.
41        unsafe {
42            try_submit(&*self.0, f);
43        }
44    }
45
46    /// Waits for all submissions to finish.
47    ///
48    /// Dropping the `Pool` will also wait for all submissions to finish.
49    pub fn join(&self) {
50        unsafe {
51            CloseThreadpoolCleanupGroupMembers(self.0.CleanupGroup, 0, core::ptr::null_mut());
52        }
53    }
54}
55
56impl Default for Pool {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62unsafe impl Sync for Pool {}
63unsafe impl Send for Pool {}
64
65impl Drop for Pool {
66    fn drop(&mut self) {
67        // The `Pool` object cannot be dropped without waiting for all closures to complete, as their
68        // lifetimes are only guaranteed to be as long as the `Pool` object.
69        self.join();
70
71        unsafe {
72            CloseThreadpoolCleanupGroup(self.0.CleanupGroup);
73            CloseThreadpool(self.0.Pool);
74        }
75    }
76}