Boost logo

Boost :

From: Gennadiy Rozental (rogeeff_at_[hidden])
Date: 2002-03-21 13:53:09


('binary' encoding is not supported, stored as-is)

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