|
Boost : |
From: Gennadiy Rozental (rogeeff_at_[hidden])
Date: 2002-03-21 13:53:09
Hi,
I was using notion of "thread pool" for a long time with my previous project. One thing that I found missing in your implementation is an ability to be more flexible in terms of amount of active threads. Min and max is not enough. I attached class object_pool that I was using for this and similar purposes. this pool is configured by "manager algorithm" that will manage among of object in the pool. I have a test module for it either if you will find it interesting.
Gennadiy.
--- "Moore, Dave" <dmoore_at_[hidden]> wrote:
>An implementation of a thread_pool (aka worker pool, worker queue) has been
>uploaded to :
>
>http://groups.yahoo.com/group/boost/files/thread_pool.zip
>
>Documentation and examples are included.
>
>Features:
>
>- Implemented purely in terms of Boost.Threads
>- A thread pool object can execute any function conforming to
>boost::function0<void>.
>- Control over the minimum and maximum number of threads used in the pool
>- thread_pool is join()able
>- cancel is provided, which currently cancels any unexecuted jobs, and will
>eventually cancel any running jobs once boost::thread::cancel() exists.
>
>
>Future Directions/Questions:
>
>- It may be a good idea to support priorities for jobs, but this should be
>done in concert with the idea of boost::thread::priority
>
>- While detach() is included in the sample implementation for completeness,
>it may not be necessary for a thread_pool. If the risks outweigh the
>utility, it may be removed.
>
>
>Warning:
>
>Requires Boost 1.27.0. On win32, a deadlock can occur when adding new
>functions to the thread pool for Boost 1.26.0
>
>
>Thanks very much to Bill Kempf for EXTENSIVE feedback and comments on the
>design.
>
>Dave
>
>
>_______________________________________________
>Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_____________________________________________________________
A free email account your friends will never forget!
Get YOURNAME_at_[hidden] at http://www.emailaccount.com/
_____________________________________________________________
Run a small business? Then you need professional email like you_at_[hidden] from Everyone.net http://www.everyone.net?tag
// (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.
#ifndef OBJECT_POOL_HPP
#define OBJECT_POOL_HPP
// BOOST
#include <boost/utility.hpp>
// STL
#include <list>
namespace common_layer {
// ************************************************************************** //
// ********* Algorithms to manage amounts of objects in the pool ********* //
// ************************************************************************** //
// We are going to use Algorithms as templete argument to the object_pool class so
// smart compiler will use static binding even though methos are virtual
class pool_management_alg {
public:
// initial amount of objects
virtual size_t init_value() = 0;
// based on amount of objects currently stored, this function define storage
// size increment
virtual size_t enlarge_storage( size_t storageSize ) = 0;
// based on amount of currently used and free object this function decide
// what do we need to do with returned after using object: leave in storage
// (return value = true) or delete and free memory (return value = false)
virtual bool hold_returned( size_t used, size_t free ) = 0;
// false means that this object is not supposed to be returned to storage at all
// example - persistent objects, that work all the time during prorgamm lifetime
virtual bool returnable() { return true; }
};
// ************************************************************************** //
template<bool lazy = false>
class fixed_length_alg : public pool_management_alg {
public:
// Constructor
explicit fixed_length_alg( size_t l ) : m_length( l ) {}
// Algorithm definition
virtual size_t init_value() { return lazy ? 0 : m_length; }
virtual size_t enlarge_storage( size_t storageSize ) { return lazy ? storageSize < m_length : 0; }
virtual bool hold_returned( size_t, size_t ) { return true; }
private:
// Data member
size_t m_length;
};
// ************************************************************************** //
class zero_length_alg : public fixed_length_alg<true> {
public:
// Constructor
zero_length_alg() : fixed_length_alg<true>( 0 ) {}
// Algorithm definition
virtual bool hold_returned( size_t, size_t ) { return false; }
};
// ************************************************************************** //
template<bool lazy = false>
class fixed_non_storing_alg : public fixed_length_alg<lazy> {
public:
// Constructor
explicit fixed_non_storing_alg( size_t l ) : fixed_length_alg<lazy>( l ) {}
// Algorithm definition
virtual bool hold_returned( size_t, size_t ) { return false; }
};
// ************************************************************************** //
template<bool lazy = false>
class non_returnable_alg : public fixed_length_alg<lazy> {
public:
// Constructor
explicit non_returnable_alg( size_t l ) : fixed_length_alg<lazy>( l ) {}
// Algorithm definition
virtual bool hold_returned( size_t, size_t ) { return false; }
virtual bool returnable() { return false; }
};
// ************************************************************************** //
class dynamic_length_alg : public pool_management_alg {
public:
// Constructor
explicit dynamic_length_alg( size_t init_value, double factor = 1, int increment = 0 )
: m_init_value( init_value ), m_factor( factor ), m_increment( increment ) {}
// Algorithm definition
virtual size_t init_value() { return m_init_value; }
// new amount = old + old/factor + increment
virtual size_t enlarge_storage( size_t storageSize )
{
size_t res = (size_t)( storageSize * m_factor + m_increment );
return res > 0 ? res : 1;
}
private:
// Data member
size_t m_init_value;
double m_factor;
int m_increment;
};
// ************************************************************************** //
class non_limiting_alg : public dynamic_length_alg {
public:
// Constructor
explicit non_limiting_alg( size_t s, double factor = 1, int increment = 0 )
: dynamic_length_alg( s, factor, increment ) {}
// Algorithm definition
virtual bool hold_returned( size_t, size_t ) { return true; }
};
// ************************************************************************** //
class non_storing_alg : public dynamic_length_alg {
public:
// Constructor
non_storing_alg() : dynamic_length_alg( 0, 1, 0 ) {}
// Algorithm definition
virtual bool hold_returned( size_t, size_t ) { return false; }
};
// ************************************************************************** //
class balancing_alg : public dynamic_length_alg {
public:
// Constructor
explicit balancing_alg( size_t s = 10, int balDiv = 2, int minimumStored = 20 )
: dynamic_length_alg( s, 1, 0 ), m_balance_factor( balDiv ), m_storage_min_size( minimumStored ) {}
// Algorithm definition
virtual bool hold_returned( size_t used, size_t free ){ return free < used * m_balance_factor ||
free < m_storage_min_size; }
private:
// Data members
double m_balance_factor;
size_t m_storage_min_size;
};
// ************************************************************************** //
// ************** default_instance_factory ************** //
// ************************************************************************** //
template<typename ObjectType>
class default_instance_factory {
public:
ObjectType* operator()() { return new ObjectType; }
};
// ************************************************************************** //
// ************** object_pool ************** //
// ************************************************************************** //
template<typename ObjectType,
class PoolManagerAlgorithm = balancing_alg,
class InstanceFactory = default_instance_factory<ObjectType> >
class object_pool : public boost::noncopyable {
public:
// Constructor
explicit object_pool( PoolManagerAlgorithm const& alg, bool delete_unused = true );
// Destructor
~object_pool();
// access methods
bool get_object( ObjectType*& obj ); // returns returnable status
bool put_object( ObjectType* obj );
size_t size();
// configuration
void set_manager_algorithm( PoolManagerAlgorithm const& alg );
private:
// typedefs
typedef std::list<ObjectType*> store_type;
typedef typename store_type::size_type size_type;
// Data members
store_type m_store;
PoolManagerAlgorithm m_manager_alg;
InstanceFactory m_factory;
int m_used_objs_amount;
bool m_delete_unused;
};
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
inline
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::
object_pool( PoolManagerAlgorithm const& alg, bool delete_unused )
: m_manager_alg( alg ), m_used_objs_amount( 0 ), m_delete_unused( delete_unused )
{
std::generate_n( std::back_inserter( m_store ), m_manager_alg.init_value(), m_factory );
}
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
inline
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::~object_pool()
{
std::for_each( m_store.begin(), m_store.end(), delete_ptr<ObjectType>() );
m_store.clear();
}
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
void
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::
set_manager_algorithm( PoolManagerAlgorithm const& alg )
{
m_manager_alg = alg;
while( m_store.size() > 1 &&
!m_manager_alg.hold_returned( m_used_objs_amount, m_store.size() - 1 ) ) {
ObjectType* to_delete = m_store.front();
m_store.pop_front();
if( m_delete_unused )
delete to_delete;
}
if( m_store.size() < m_manager_alg.init_value() ) {
std::generate_n( std::back_inserter( m_store ), m_manager_alg.init_value() - m_store.size(), m_factory );
}
}
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
inline bool
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::get_object( ObjectType*& obj )
{
// 1. Initialize out object with default value
// 2. If pool is empty, try to refill it
// 3. If pool is not empty, take first available object
// 4. If we found object increase number of used object
// 5. No need to return object if result object is NULL
obj = NULL; // 1 //
if( m_store.size() == 0 ) { // 2 //
std::generate_n( std::back_inserter( m_store ),
m_manager_alg.enlarge_storage( m_used_objs_amount ),
m_factory );
}
if( m_store.size() > 0 ) { // 3 //
obj = m_store.front();
m_store.pop_front();
}
if( obj != NULL ) // 4 //
m_used_objs_amount++;
return obj != NULL && m_manager_alg.returnable(); // 5 //
}
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
inline bool
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::put_object( ObjectType* obj )
{
if( obj == NULL )
return false;
m_used_objs_amount--;
if( m_manager_alg.hold_returned( m_used_objs_amount, m_store.size() ) ) {
m_store.push_front( obj );
return true;
}
else {
if( m_delete_unused )
delete obj;
return false;
}
}
//____________________________________________________________________________//
template<typename ObjectType, class PoolManagerAlgorithm, class ObjectFatory>
inline size_t
object_pool<ObjectType,PoolManagerAlgorithm,ObjectFatory>::size()
{
return m_store.size();
}
//____________________________________________________________________________//
} // namespace common_layer
#endif // OBJECT_POOL_HPP
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk