ThreadPool.h
Go to the documentation of this file.
1 //=================================================================================================
33 //=================================================================================================
34 
35 #ifndef _BLAZE_UTIL_THREADPOOL_THREADPOOL_H_
36 #define _BLAZE_UTIL_THREADPOOL_THREADPOOL_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <functional>
44 #include <memory>
45 #include <vector>
46 #include <blaze/util/Assert.h>
47 #include <blaze/util/Exception.h>
48 #include <blaze/util/NonCopyable.h>
50 #include <blaze/util/Thread.h>
53 #include <blaze/util/Types.h>
54 
55 
56 namespace blaze {
57 
58 //=================================================================================================
59 //
60 // CLASS DEFINITION
61 //
62 //=================================================================================================
63 
64 //*************************************************************************************************
307 template< typename TT // Type of the encapsulated thread
308  , typename MT // Type of the synchronization mutex
309  , typename LT // Type of the mutex lock
310  , typename CT > // Type of the condition variable
311 class ThreadPool
312  : private NonCopyable
313 {
314  private:
315  //**Type definitions****************************************************************************
318 
320  using Threads = std::vector< std::unique_ptr<ManagedThread> >;
321 
323  using Mutex = MT;
324  using Lock = LT;
325  using Condition = CT;
326  //**********************************************************************************************
327 
328  public:
329  //**Constructor*********************************************************************************
332  explicit ThreadPool( size_t n );
334  //**********************************************************************************************
335 
336  //**Destructor**********************************************************************************
339  ~ThreadPool();
341  //**********************************************************************************************
342 
343  //**Get functions*******************************************************************************
346  inline bool isEmpty() const;
347  inline size_t size() const;
348  inline size_t active() const;
349  inline size_t ready() const;
351  //**********************************************************************************************
352 
353  //**Task scheduling*****************************************************************************
356  template< typename Callable, typename... Args >
357  void schedule( Callable func, Args&&... args );
359  //**********************************************************************************************
360 
361  //**Utility functions***************************************************************************
364  void resize( size_t n, bool block=false );
365  void wait();
366  void clear();
368  //**********************************************************************************************
369 
370  private:
371  //**Thread functions****************************************************************************
374  void createThread();
375  bool executeTask();
377  //**********************************************************************************************
378 
379  //**Member variables****************************************************************************
382  volatile size_t total_;
383  volatile size_t expected_;
384 
386  volatile size_t active_;
389  mutable Mutex mutex_;
392 
393  //**********************************************************************************************
394 
395  //**Friend declarations*************************************************************************
397  friend class Thread<TT,MT,LT,CT>;
399  //**********************************************************************************************
400 };
401 //*************************************************************************************************
402 
403 
404 
405 
406 //=================================================================================================
407 //
408 // CONSTRUCTOR
409 //
410 //=================================================================================================
411 
412 //*************************************************************************************************
420 template< typename TT // Type of the encapsulated thread
421  , typename MT // Type of the synchronization mutex
422  , typename LT // Type of the mutex lock
423  , typename CT > // Type of the condition variable
425  : total_ ( 0UL ) // Total number of threads in the thread pool
426  , expected_( 0UL ) // Expected number of threads in the thread pool
427  , active_ ( 0UL ) // Number of currently active/busy threads
428  , threads_ () // The threads contained in the thread pool
429  , taskqueue_ () // Task queue for the scheduled tasks
430  , mutex_ () // Synchronization mutex
431  , waitForTask_ () // Wait condition for idle threads
432  , waitForThread_() // Wait condition for the thread management
433 {
434  resize( n );
435 }
436 //*************************************************************************************************
437 
438 
439 
440 
441 //=================================================================================================
442 //
443 // DESTRUCTOR
444 //
445 //=================================================================================================
446 
447 //*************************************************************************************************
453 template< typename TT // Type of the encapsulated thread
454  , typename MT // Type of the synchronization mutex
455  , typename LT // Type of the mutex lock
456  , typename CT > // Type of the condition variable
458 {
459  Lock lock( mutex_ );
460 
461  // Removing all currently queued tasks
462  taskqueue_.clear();
463 
464  // Setting the expected number of threads
465  expected_ = 0UL;
466 
467  // Notifying all idle threads
468  waitForTask_.notify_all();
469 
470  // Waiting for all threads to terminate
471  while( total_ != 0UL ) {
472  waitForThread_.wait( lock );
473  }
474 
475  // Joining all threads
476  for( auto const& thread : threads_ ) {
477  thread->join();
478  }
479 
480  // Destroying all threads
481  threads_.clear();
482 }
483 //*************************************************************************************************
484 
485 
486 
487 
488 //=================================================================================================
489 //
490 // GET FUNCTIONS
491 //
492 //=================================================================================================
493 
494 //*************************************************************************************************
499 template< typename TT // Type of the encapsulated thread
500  , typename MT // Type of the synchronization mutex
501  , typename LT // Type of the mutex lock
502  , typename CT > // Type of the condition variable
504 {
505  Lock lock( mutex_ );
506  return taskqueue_.isEmpty();
507 }
508 //*************************************************************************************************
509 
510 
511 //*************************************************************************************************
516 template< typename TT // Type of the encapsulated thread
517  , typename MT // Type of the synchronization mutex
518  , typename LT // Type of the mutex lock
519  , typename CT > // Type of the condition variable
520 inline size_t ThreadPool<TT,MT,LT,CT>::size() const
521 {
522  Lock lock( mutex_ );
523  return expected_;
524 }
525 //*************************************************************************************************
526 
527 
528 //*************************************************************************************************
533 template< typename TT // Type of the encapsulated thread
534  , typename MT // Type of the synchronization mutex
535  , typename LT // Type of the mutex lock
536  , typename CT > // Type of the condition variable
537 inline size_t ThreadPool<TT,MT,LT,CT>::active() const
538 {
539  Lock lock( mutex_ );
540  return active_;
541 }
542 //*************************************************************************************************
543 
544 
545 //*************************************************************************************************
550 template< typename TT // Type of the encapsulated thread
551  , typename MT // Type of the synchronization mutex
552  , typename LT // Type of the mutex lock
553  , typename CT > // Type of the condition variable
554 inline size_t ThreadPool<TT,MT,LT,CT>::ready() const
555 {
556  Lock lock( mutex_ );
557  return expected_ - active_;
558 }
559 //*************************************************************************************************
560 
561 
562 
563 
564 //=================================================================================================
565 //
566 // SCHEDULING FUNCTIONS
567 //
568 //=================================================================================================
569 
570 //*************************************************************************************************
581 template< typename TT // Type of the encapsulated thread
582  , typename MT // Type of the synchronization mutex
583  , typename LT // Type of the mutex lock
584  , typename CT > // Type of the condition variable
585 template< typename Callable // Type of the function/functor
586  , typename... Args > // Types of the function/functor arguments
587 void ThreadPool<TT,MT,LT,CT>::schedule( Callable func, Args&&... args )
588 {
589  Lock lock( mutex_ );
590  taskqueue_.push( std::bind<void>( func, std::forward<Args>( args )... ) );
591  waitForTask_.notify_one();
592 }
593 //*************************************************************************************************
594 
595 
596 
597 
598 //=================================================================================================
599 //
600 // UTILITY FUNCTIONS
601 //
602 //=================================================================================================
603 
604 //*************************************************************************************************
644 template< typename TT // Type of the encapsulated thread
645  , typename MT // Type of the synchronization mutex
646  , typename LT // Type of the mutex lock
647  , typename CT > // Type of the condition variable
648 void ThreadPool<TT,MT,LT,CT>::resize( size_t n, bool block )
649 {
650  // Checking the given number of threads
651 #if !(defined _MSC_VER)
652  if( n == 0UL ) {
653  BLAZE_THROW_INVALID_ARGUMENT( "Invalid number of threads" );
654  }
655 #endif
656 
657  // Adjusting the number of threads
658  {
659  Lock lock( mutex_ );
660 
661  // Adding new threads to the thread pool
662  if( n > expected_ ) {
663  for( size_t i=expected_; i<n; ++i )
664  createThread();
665  }
666 
667  // Removing threads from the pool
668  else {
669  expected_ = n;
670  waitForTask_.notify_all();
671 
672  while( block && total_ != expected_ ) {
673  waitForThread_.wait( lock );
674  }
675  }
676 
677  // Joining and destroying any terminated thread
678  for( typename Threads::iterator thread=threads_.begin(); thread!=threads_.end(); ) {
679  if( (*thread)->hasTerminated() ) {
680  (*thread)->join();
681  thread = threads_.erase( thread );
682  }
683  else ++thread;
684  }
685  }
686 }
687 //*************************************************************************************************
688 
689 
690 //*************************************************************************************************
697 template< typename TT // Type of the encapsulated thread
698  , typename MT // Type of the synchronization mutex
699  , typename LT // Type of the mutex lock
700  , typename CT > // Type of the condition variable
702 {
703  Lock lock( mutex_ );
704 
705  while( !taskqueue_.isEmpty() || active_ > 0UL ) {
706  waitForThread_.wait( lock );
707  }
708 }
709 //*************************************************************************************************
710 
711 
712 //*************************************************************************************************
720 template< typename TT // Type of the encapsulated thread
721  , typename MT // Type of the synchronization mutex
722  , typename LT // Type of the mutex lock
723  , typename CT > // Type of the condition variable
725 {
726  Lock lock( mutex_ );
727  taskqueue_.clear();
728 }
729 //*************************************************************************************************
730 
731 
732 
733 
734 //=================================================================================================
735 //
736 // THREAD FUNCTIONS
737 //
738 //=================================================================================================
739 
740 //*************************************************************************************************
745 template< typename TT // Type of the encapsulated thread
746  , typename MT // Type of the synchronization mutex
747  , typename LT // Type of the mutex lock
748  , typename CT > // Type of the condition variable
750 {
751  threads_.push_back( std::unique_ptr<ManagedThread>( new ManagedThread( this ) ) );
752  ++total_;
753  ++expected_;
754  ++active_;
755 }
756 //*************************************************************************************************
757 
758 
759 //*************************************************************************************************
768 template< typename TT // Type of the encapsulated thread
769  , typename MT // Type of the synchronization mutex
770  , typename LT // Type of the mutex lock
771  , typename CT > // Type of the condition variable
773 {
774  threadpool::Task task;
775 
776  // Acquiring a scheduled task
777  {
778  Lock lock( mutex_ );
779 
780  while( taskqueue_.isEmpty() )
781  {
782  --active_;
783  waitForThread_.notify_all();
784 
785  if( total_ > expected_ ) {
786  --total_;
787  return false;
788  }
789 
790  waitForTask_.wait( lock );
791  ++active_;
792  }
793 
794  BLAZE_INTERNAL_ASSERT( !taskqueue_.isEmpty(), "Empty task queue detected" );
795  task = taskqueue_.pop();
796  }
797 
798  // Executing the task
799  task();
800 
801  return true;
802 }
803 //*************************************************************************************************
804 
805 } // namespace blaze
806 
807 #endif
#define BLAZE_THROW_INVALID_ARGUMENT(MESSAGE)
Macro for the emission of a std::invalid_argument exception.This macro encapsulates the default way o...
Definition: Exception.h:235
Header file for basic type definitions.
Thread< TT, MT, LT, CT > ManagedThread
Type of the managed threads.
Definition: ThreadPool.h:317
bool isEmpty() const
Returns true if the task queue has no elements.
Definition: TaskQueue.h:202
Condition waitForTask_
Wait condition for idle threads.
Definition: ThreadPool.h:390
void clear()
Removing all scheduled tasks from the thread pool.
Definition: ThreadPool.h:724
CT Condition
Condition variable type.
Definition: ThreadPool.h:325
Header file for exception macros.
Base class for non-copyable class instances.
void createThread()
Adding a new thread to the thread pool.
Definition: ThreadPool.h:749
size_t size() const
Returns the current size of the thread pool.
Definition: ThreadPool.h:520
Task pop()
Returns the task from the front of the task queue.
Definition: TaskQueue.h:237
Mutex mutex_
Synchronization mutex.
Definition: ThreadPool.h:389
void resize(size_t n, bool block=false)
Changes the total number of threads in the thread pool.
Definition: ThreadPool.h:648
std::vector< std::unique_ptr< ManagedThread > > Threads
Type of the thread container.
Definition: ThreadPool.h:320
volatile size_t active_
Number of currently active/busy threads.
Definition: ThreadPool.h:386
bool executeTask()
Executing a scheduled task.
Definition: ThreadPool.h:772
volatile size_t expected_
Expected number of threads in the thread pool.
Definition: ThreadPool.h:383
Task queue for the thread pool.
~ThreadPool()
Destructor for the ThreadPool class.
Definition: ThreadPool.h:457
std::function< void(void)> Task
Handle for a single, executable task.
Definition: Task.h:60
Namespace of the Blaze C++ math library.
Definition: Blaze.h:57
Compile time assertion.
Header file for the Thread class.
Condition waitForThread_
Wait condition for the thread management.
Definition: ThreadPool.h:391
Implementation of a single thread of execution.
Definition: Thread.h:250
size_t active() const
Returns the number of currently active/busy threads.
Definition: ThreadPool.h:537
ThreadPool(size_t n)
Constructor for the ThreadPool class.
Definition: ThreadPool.h:424
size_t ready() const
Returns the number of currently ready/inactive threads.
Definition: ThreadPool.h:554
bool isEmpty() const
Returns whether any tasks are scheduled for execution.
Definition: ThreadPool.h:503
void schedule(Callable func, Args &&... args)
Scheduling the given function/functor for execution.
Definition: ThreadPool.h:587
Header file for run time assertion macros.
Threads threads_
The threads contained in the thread pool.
Definition: ThreadPool.h:387
Header file for the Task base class.
void wait()
Waiting for all scheduled tasks to be completed.
Definition: ThreadPool.h:701
volatile size_t total_
Total number of threads in the thread pool.
Definition: ThreadPool.h:382
void push(Task task)
Adding a task to the end of the task queue.
Definition: TaskQueue.h:225
Task queue for the thread pool.The TaskQueue class represents the internal task container of a thread...
Definition: TaskQueue.h:64
TaskQueue taskqueue_
Task queue for the scheduled tasks.
Definition: ThreadPool.h:388
void clear()
Removing all tasks from the task queue.
Definition: TaskQueue.h:251
MT Mutex
Type of the mutex.
Definition: ThreadPool.h:323
#define BLAZE_INTERNAL_ASSERT(expr, msg)
Run time assertion macro for internal checks.In case of an invalid run time expression, the program execution is terminated. The BLAZE_INTERNAL_ASSERT macro can be disabled by setting the BLAZE_USER_ASSERTION flag to zero or by defining NDEBUG during the compilation.
Definition: Assert.h:101
LT Lock
Type of a locking object.
Definition: ThreadPool.h:324