@@ -69,6 +69,7 @@ use std::any::Any;
6969use std:: collections:: VecDeque ;
7070use std:: marker:: PhantomData ;
7171use std:: panic:: { AssertUnwindSafe , catch_unwind, resume_unwind} ;
72+ use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
7273use std:: sync:: mpsc:: { SyncSender , TrySendError } ;
7374use std:: sync:: { Arc , Condvar , Mutex } ;
7475
@@ -111,7 +112,7 @@ where
111112
112113/// Scope to spawn tasks in.
113114///
114- /// Designed to match the [`std::thread::Scope`] API.
115+ /// [`Scope::spawn()`] is designed to match the [`std::thread::Scope`] API.
115116///
116117/// # Lifetimes
117118///
@@ -147,6 +148,55 @@ impl<'scope> Scope<'scope, '_> {
147148 handle
148149 }
149150
151+ /// Spawn a new task within the scope if there is a worker available.
152+ ///
153+ /// If no workers within the thread pool are available, the task will not be executed and
154+ /// [`None`] will be returned.
155+ pub fn try_spawn < F , T > ( & ' scope self , f : F ) -> Option < ScopedJoinHandle < ' scope , T > >
156+ where
157+ F : FnOnce ( ) -> T + Send + ' scope ,
158+ T : Send + ' scope ,
159+ {
160+ let ( closure, handle) = self . create_closure ( f) ;
161+ if let Ok ( ( ) ) = try_queue_task ( closure) {
162+ Some ( handle)
163+ } else {
164+ // Closure will never be run
165+ self . data . task_end ( ) ;
166+
167+ None
168+ }
169+ }
170+
171+ /// Spawn a new task within the scope, spawning a new worker if necessary.
172+ ///
173+ /// This function is not available on WebAssembly, as new threads have to be created from the
174+ /// host JS environment.
175+ #[ cfg( not( target_family = "wasm" ) ) ]
176+ pub fn force_spawn < F , T > ( & ' scope self , f : F ) -> ScopedJoinHandle < ' scope , T >
177+ where
178+ F : FnOnce ( ) -> T + Send + ' scope ,
179+ T : Send + ' scope ,
180+ {
181+ let ( closure, handle) = self . create_closure ( f) ;
182+ if let Err ( closure) = try_queue_task ( closure) {
183+ // Start a worker to process this closure and then join the pool.
184+ static THREAD_NUM : AtomicU32 = AtomicU32 :: new ( 1 ) ;
185+ std:: thread:: Builder :: new ( )
186+ . name ( format ! (
187+ "scoped-tasks-{}" ,
188+ THREAD_NUM . fetch_add( 1 , Ordering :: Relaxed )
189+ ) )
190+ . spawn ( move || {
191+ // Pass the closure directly to the new worker to avoid race conditions where
192+ // another scope queues a closure before this one.
193+ worker_impl ( closure) ;
194+ } )
195+ . expect ( "failed to spawn worker thread" ) ;
196+ }
197+ handle
198+ }
199+
150200 fn create_closure < F , T > (
151201 & ' scope self ,
152202 f : F ,
@@ -345,6 +395,12 @@ fn try_queue_task(mut closure: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn F
345395///
346396/// This function never returns.
347397pub fn worker ( ) {
398+ worker_impl ( || { } ) ;
399+ }
400+
401+ fn worker_impl ( initial : impl FnOnce ( ) + Send ) {
402+ initial ( ) ;
403+
348404 let ( tx, rx) = std:: sync:: mpsc:: sync_channel ( 0 ) ;
349405
350406 {
0 commit comments