pub fn spawn_thread(&self, id: WorkerId, pool: &Arc<Pool>) {
        debug_assert_eq!(*self, **pool);

        let backup_id = match self.backup_stack.pop(&self.backup, false) {
            Ok(Some(backup_id)) => backup_id,
            Ok(None) => panic!("no thread available"),
            Err(_) => {
                debug!("failed to spawn worker thread due to the thread pool shutting down");
                return;
            }
        };

        let need_spawn = self.backup[backup_id.0].worker_handoff(id.clone());

        if !need_spawn {
            return;
        }

        let trigger = match self.trigger.upgrade() {
            None => {
                // The pool is shutting down.
                return;
            }
            Some(t) => t,
        };

        let mut th = thread::Builder::new();

        if let Some(ref prefix) = pool.config.name_prefix {
            th = th.name(format!("{}{}", prefix, backup_id.0));
        }

        if let Some(stack) = pool.config.stack_size {
            th = th.stack_size(stack);
        }

        let pool = pool.clone();

        let res = th.spawn(move || {
            if let Some(ref f) = pool.config.after_start {
                f();
            }

            let mut worker_id = id;

            pool.backup[backup_id.0].start(&worker_id);

            loop {
                // The backup token should be in the running state.
                debug_assert!(pool.backup[backup_id.0].is_running());

                // TODO: Avoid always cloning
                let worker = Worker::new(worker_id, backup_id, pool.clone(), trigger.clone());

                // Run the worker. If the worker transitioned to a "blocking"
                // state, then `is_blocking` will be true.
                if !worker.do_run() {
                    // The worker shutdown, so exit the thread.
                    break;
                }

                debug_assert!(!pool.backup[backup_id.0].is_pushed());

                // Push the thread back onto the backup stack. This makes it
                // available for future handoffs.
                //
                // This **must** happen before notifying the task.
                let res = pool.backup_stack.push(&pool.backup, backup_id);

                if res.is_err() {
                    // The pool is being shutdown.
                    break;
                }

                // The task switched the current thread to blocking mode.
                // Now that the blocking task completed, any tasks
                pool.notify_blocking_task(&pool);

                debug_assert!(pool.backup[backup_id.0].is_running());

                // Wait for a handoff
                let handoff = pool.backup[backup_id.0].wait_for_handoff(pool.config.keep_alive);

                match handoff {
                    Handoff::Worker(id) => {
                        debug_assert!(pool.backup[backup_id.0].is_running());
                        worker_id = id;
                    }
                    Handoff::Idle | Handoff::Terminated => {
                        break;
                    }
                }
            }

            if let Some(ref f) = pool.config.before_stop {
                f();
            }
        });

        if let Err(e) = res {
            error!("failed to spawn worker thread; err={:?}", e);
            panic!("failed to spawn worker thread: {:?}", e);
        }
    }
/// Provision a thread to run a worker
Provision a thread to run a worker
Provision a thread to run a worker
pub fn spawn_thread(&self, id: WorkerId, pool: &Arc<Pool>) {
        debug_assert_eq!(*self, **pool);
        let backup_id = match self.backup_stack.pop(&self.backup, false) {
            Ok(Some(backup_id)) => backup_id,
            Ok(None) => panic!("no thread available"),
            Err(_) => {
                debug!("failed to spawn worker thread due to the thread pool shutting down");
                return;
            }
        };
        let need_spawn = self.backup[backup_id.0].worker_handoff(id.clone());
        if !need_spawn {
            return;
        }
        let trigger = match self.trigger.upgrade() {
            None => {
                // The pool is shutting down.
                return;
            }
            Some(t) => t,
        };
        let mut th = thread::Builder::new();
        if let Some(ref prefix) = pool.config.name_prefix {
            th = th.name(format!("{}{}", prefix, backup_id.0));
        }
        if let Some(stack) = pool.config.stack_size {
            th = th.stack_size(stack);
        }
        let pool = pool.clone();
        let res = th.spawn(move || {
            if let Some(ref f) = pool.config.after_start {
                f();
            }
            let mut worker_id = id;
            pool.backup[backup_id.0].start(&worker_id);
            loop {
                // The backup token should be in the running state.
                debug_assert!(pool.backup[backup_id.0].is_running());
                // TODO: Avoid always cloning
                let worker = Worker::new(worker_id, backup_id, pool.clone(), trigger.clone());
                // Run the worker. If the worker transitioned to a "blocking"
                // state, then `is_blocking` will be true.
                if !worker.do_run() {
                    // The worker shutdown, so exit the thread.
                    break;
                }
                debug_assert!(!pool.backup[backup_id.0].is_pushed());
                // Push the thread back onto the backup stack. This makes it
                // available for future handoffs.
                //
                // This **must** happen before notifying the task.
                let res = pool.backup_stack.push(&pool.backup, backup_id);
                if res.is_err() {
                    // The pool is being shutdown.
                    break;
                }
                // The task switched the current thread to blocking mode.
                // Now that the blocking task completed, any tasks
                pool.notify_blocking_task(&pool);
                debug_assert!(pool.backup[backup_id.0].is_running());
                // Wait for a handoff
                let handoff = pool.backup[backup_id.0].wait_for_handoff(pool.config.keep_alive);
                match handoff {
                    Handoff::Worker(id) => {
                        debug_assert!(pool.backup[backup_id.0].is_running());
                        worker_id = id;
                    }
                    Handoff::Idle | Handoff::Terminated => {
                        break;
                    }
                }
            }
            if let Some(ref f) = pool.config.before_stop {
                f();
            }
        });
        if let Err(e) = res {
            error!("failed to spawn worker thread; err={:?}", e);
            panic!("failed to spawn worker thread: {:?}", e);
        }
    }
pub fn spawn_thread ( & self , id : WorkerId , pool : & Arc < Pool > ) { debug_assert_eq ! ( self pool ) ; let backup_id = match self . backup_stack . pop ( & self . backup , false ) { Ok ( Some ( backup_id ) ) => backup_id , Ok ( None ) => panic ! ( " " ) , Err ( _ ) => { debug ! ( " " ) ; return ; } } ; let need_spawn = self . backup [ backup_id . 0 ] . worker_handoff ( id . clone ( ) ) ; if ! need_spawn { return ; } let trigger = match self . trigger . upgrade ( ) { None => { // The pool is shutting down. return ; } Some ( t ) => t , } ; let mut th = thread :: Builder :: new ( ) ; if let Some ( ref prefix ) = pool . config . name_prefix { th = th . name ( format ! ( " " prefix backup_id 0 ) ) ; } if let Some ( stack ) = pool . config . stack_size { th = th . stack_size ( stack ) ; } let pool = pool . clone ( ) ; let res = th . spawn ( move | | { if let Some ( ref f ) = pool . config . after_start { f ( ) ; } let mut worker_id = id ; pool . backup [ backup_id . 0 ] . start ( & worker_id ) ; loop { // The backup token should be in the running state. debug_assert ! ( pool backup [ backup_id 0 ] is_running ( ) ) ; // TODO: Avoid always cloning let worker = Worker :: new ( worker_id , backup_id , pool . clone ( ) , trigger . clone ( ) ) ; // Run the worker. If the worker transitioned to a "blocking" // state, then `is_blocking` will be true. if ! worker . do_run ( ) { // The worker shutdown, so exit the thread. break ; } debug_assert ! ( pool backup [ backup_id 0 ] is_pushed ( ) ) ; // Push the thread back onto the backup stack. This makes it // available for future handoffs. // // This **must** happen before notifying the task. let res = pool . backup_stack . push ( & pool . backup , backup_id ) ; if res . is_err ( ) { // The pool is being shutdown. break ; } // The task switched the current thread to blocking mode. // Now that the blocking task completed, any tasks pool . notify_blocking_task ( & pool ) ; debug_assert ! ( pool backup [ backup_id 0 ] is_running ( ) ) ; // Wait for a handoff let handoff = pool . backup [ backup_id . 0 ] . wait_for_handoff ( pool . config . keep_alive ) ; match handoff { Handoff :: Worker ( id ) => { debug_assert ! ( pool backup [ backup_id 0 ] is_running ( ) ) ; worker_id = id ; } Handoff :: Idle | Handoff :: Terminated => { break ; } } } if let Some ( ref f ) = pool . config . before_stop { f ( ) ; } } ) ; if let Err ( e ) = res { error ! ( " " e ) ; panic ! ( " " e ) ; } }
Provision a thread to run a worker
Provision a thread to run a worker
&self
id
WorkerId
pool
&Arc<Pool>