// pool_policy // // Original pool_management_alg concept and design: // (C) Copyright Gennadiy Rozental 2002. // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied warranty, // and with no claim as to its suitability for any purpose. class pool_policy { public: // return an initial number of objects to create in the pool. virtual size_t init_count() = 0; // return the amount of (seconds? millseconds?) time that an idle object // should be held in the pool. // If 0 is returned, then threads will immediately be considered idle // if there is no more work to do. virtual int idle_time() = 0; // Given a current size of a pool and the length of the backlog, this function // returns how many more items to create. Assumption is that this is called when nothing is idle. // virtual size_t enlarge_by( size_t current_size, size_t jobqueue_size ) = 0; // Given a current overall size of a pool, and given a count of idle objects, // make a determination as to whether the object should be discarded from // the pool. virtual bool should_discard( size_t current_size, size_t idle_count); }; // Example of two concrete policies // min_max_timed_policy - A concrete realization of the existing thread_pool mechanism. class min_max_timed_policy { public: min_max_timed_policy(int max_threads=std::numeric_limits::max(), int min_threads=0, int timeout_secs=5) : m_min(min_threads), m_max(max_threads), m_timeout(timeout_secs) {} virtual size_t init_count() {return m_min;} virtual int idle_time() {return m_timeout;} virtual size_t enlarge_by( size_t current_size, size_t /*jobqueue_size*/ ) { return current_size < m_max ? 1:0;} virtual bool should_discard( size_t current_size, size_t /*idle_count*/) { return (current_size > m_min); } private: int m_min; int m_max; int m_timeout; }; // limit_backlog_policy - allow the backlog to grow to a certain point, and only then // add a thread. class limit_backlog_policy { public: limit_backlog_policy(int max_backlog) : m_backlog(backlog) {} virtual size_t init_count() {return 1;} virtual int idle_time() {return 0;} virtual size_t enlarge_by( size_t /*current_size*/, size_t jobqueue_size ) { return jobqueue_size >= m_backlog ? 1:0;} virtual bool should_discard( size_t /*current_size */, size_t /*idle_count*/) { return false; } private: int m_backlog; }; // Impact on thread_pool: class thread_pool { public: thread_pool(pool_policy *p_policy) : m_ppolicy(p_policy) { // check m_ppolicy->init_count() to see how many threads to launch } void add() { // Enqueue Job. if(idle_count) // Policy doesn't matter! Dispatch work to idle thread else // check m_ppolicy->enlarge_by() to see how many threads to launch } void join(), void detach(), void cancel() { // Policy doesn't matter. Take appropriate actions. } void _worker_harness() { while(1) { // check m_ppolicy->idle_time. while(no_work) { wait(m_ppolicy->idle_time) if(timeout) { // check m_ppolicy->should_discard() to see if we should // exit } } do_work() if(no_work && joining || no_work && detaching) { // exit w/o consulting should_discard() } } } private: pool_policy *m_ppolicy; } // User of thread pool: boost::min_max_timed_policy p(100,10,5); boost::thread_pool tp(&p);