pub fn join(&self) {
        // fast path requires no mutex
        if self.shared_data.has_work() == false {
            return ();
        }

        let generation = self.shared_data.join_generation.load(Ordering::SeqCst);
        let mut lock = self.shared_data.empty_trigger.lock().unwrap();

        while generation == self.shared_data.join_generation.load(Ordering::Relaxed)
            && self.shared_data.has_work()
        {
            lock = self.shared_data.empty_condvar.wait(lock).unwrap();
        }

        // increase generation if we are the first thread to come out of the loop
        self.shared_data.join_generation.compare_and_swap(
            generation,
            generation.wrapping_add(1),
            Ordering::SeqCst,
        );
    }
/// Block the current thread until all jobs in the pool have been executed.
///
/// Calling `join` on an empty pool will cause an immediate return.
/// `join` may be called from multiple threads concurrently.
/// A `join` is an atomic point in time. All threads joining before the join
/// event will exit together even if the pool is processing new jobs by the
/// time they get scheduled.
///
/// Calling `join` from a thread within the pool will cause a deadlock. This
/// behavior is considered safe.
///
/// # Examples
///
/// ```
/// use threadpool::ThreadPool;
/// use std::sync::Arc;
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let pool = ThreadPool::new(8);
/// let test_count = Arc::new(AtomicUsize::new(0));
///
/// for _ in 0..42 {
///     let test_count = test_count.clone();
///     pool.execute(move || {
///         test_count.fetch_add(1, Ordering::Relaxed);
///     });
/// }
///
/// pool.join();
/// assert_eq!(42, test_count.load(Ordering::Relaxed));
/// ```
Block the current thread until all jobs in the pool have been executed.
Calling `join` on an empty pool will cause an immediate return.
`join` may be called from multiple threads concurrently.
A `join` is an atomic point in time. All threads joining before the join
event will exit together even if the pool is processing new jobs by the
time they get scheduled.

Calling `join` from a thread within the pool will cause a deadlock. This
behavior is considered safe.
Block the current thread until all jobs in the pool have been executed . Calling ` join ` on an empty pool will cause an immediate return . ` join ` may be called from multiple threads concurrently . A ` join ` is an atomic point in time . All threads joining before the join event will exit together even if the pool is processing new jobs by the time they get scheduled . Calling ` join ` from a thread within the pool will cause a deadlock . This behavior is considered safe .
pub fn join(&self) {
        // fast path requires no mutex
        if self.shared_data.has_work() == false {
            return ();
        }
        let generation = self.shared_data.join_generation.load(Ordering::SeqCst);
        let mut lock = self.shared_data.empty_trigger.lock().unwrap();
        while generation == self.shared_data.join_generation.load(Ordering::Relaxed)
            && self.shared_data.has_work()
        {
            lock = self.shared_data.empty_condvar.wait(lock).unwrap();
        }
        // increase generation if we are the first thread to come out of the loop
        self.shared_data.join_generation.compare_and_swap(
            generation,
            generation.wrapping_add(1),
            Ordering::SeqCst,
        );
    }
pub fn join ( & self ) { // fast path requires no mutex if self . shared_data . has_work ( ) == false { return ( ) ; } let generation = self . shared_data . join_generation . load ( Ordering :: SeqCst ) ; let mut lock = self . shared_data . empty_trigger . lock ( ) . unwrap ( ) ; while generation == self . shared_data . join_generation . load ( Ordering :: Relaxed ) && self . shared_data . has_work ( ) { lock = self . shared_data . empty_condvar . wait ( lock ) . unwrap ( ) ; } // increase generation if we are the first thread to come out of the loop self . shared_data . join_generation . compare_and_swap ( generation , generation . wrapping_add ( 1 ) , Ordering :: SeqCst , ) ; }
Block the current thread until all jobs in the pool have been executed.
Block the current thread until all jobs in the pool have been executed .
&self
&self
examples
```
use threadpool::ThreadPool;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}.

let pool = ThreadPool::new(8);
let test_count = Arc::new(AtomicUsize::new(0)).

for _ in 0..42 {
let test_count = test_count.clone();
pool.execute(move || {
test_count.fetch_add(1, Ordering::Relaxed);
});
}

pool.join();
assert_eq!(42, test_count.load(Ordering::Relaxed));
```
` ` ` use threadpool :: ThreadPool ; use std :: sync :: Arc ; use std :: sync :: atomic :: { AtomicUsize Ordering } . let pool = ThreadPool :: new ( 8 ) ; let test_count = Arc :: new ( AtomicUsize :: new ( 0 )) . for _ in 0 .. 42 { let test_count = test_count . clone () ; pool . execute ( move || { test_count . fetch_add ( 1 Ordering :: Relaxed ) ; } ) ; } pool . join () ; assert_eq! ( 42 test_count . load ( Ordering :: Relaxed )) ; ` ` `