diff --git a/README.md b/README.md index 02d8549..7896f6a 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,18 @@ Support for futures is based on an approach sketched out by members of the `rayo Forte is distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE-APACHE and LICENSE-MIT for details. Opening a pull request is assumed to signal agreement with these licensing terms. + +## Shutdown semantics + +Heap-allocated jobs created via `HeapJob::into_job_ref` are owned by the +job reference and will be dropped when executed. If a `JobRef` is placed +into the shared injector but never executed (for example, if the pool is +shut down before the job is drained) the allocation may be leaked. This is +an intentional tradeoff to avoid adding complex bookkeeping to the fast +path of job scheduling. + +If you need to ensure that all remaining shared jobs are executed (and thus +freed) before shutdown, call `ThreadPool::drain_execute()` which will run +remaining shared jobs on the calling thread. Note this drains only the +shared injector queue; work that remains in other workers' local deques may +not be reachable by this call. diff --git a/src/thread_pool.rs b/src/thread_pool.rs index 24017fa..b32d75a 100644 --- a/src/thread_pool.rs +++ b/src/thread_pool.rs @@ -647,6 +647,22 @@ impl ThreadPool { work.spawn(self, None) } + /// Drain and execute any remaining shared jobs on the calling thread. + /// + /// This is useful during shutdown if you want to ensure that heap-allocated + /// jobs are actually executed (and therefore dropped) rather than being + /// leaked in the shared queue. This will claim a temporary worker for the + /// current thread and execute items from the shared queue until it is + /// empty. Note that this only drains the shared injector queue; jobs that + /// remain in other workers' local deques cannot be accessed here. + pub fn drain_execute(&'static self) { + self.with_worker(|worker| { + while let Some(job_ref) = self.shared_jobs.pop() { + worker.execute(job_ref, true); + } + }) + } + /// Blocks the thread waiting for a future to complete. /// /// See also: [`Worker::block_on`] and [`block_on`].