Boost logo

Boost Users :

Subject: Re: [Boost-users] Object pools?
From: Ryan McConnehey (mccorywork_at_[hidden])
Date: 2010-02-18 22:13:24


Igore Dmit. wrote:
As I understand your case is multiple buffers used in async operations in boost::asio.
First: to gain performance, you need some reusable objects pool mechanics to avoid constant allocation/deallocation of memory used by buffers.
Second: buffers must survive pool destruction while being used.
Am I correct?
You are correct.

To template or not is totally up to you :) Do you need some generic reusable code(could take some time to develop) or you need fast feature implementation and move further?
The template question had more to do with the operator function having a T*. 

If I'm correct about your case I'd like to post some more code:

typedef shared_ptr<asio::buffer> buffer_ptr;

class PoolBufferDeleter
{
private:
    weak_ptr<Pool> pool;
public:
    PoolBufferDeleter(const shared_ptr<Pool> &p) : pool(p) {}
    void operator()(asio::buffer *buf) {
        shared_ptr<Pool> shared_pool = this->pool.lock();
        if(shared_pool)
            shared_pool->deallocate(buf);
        else {
            free(asio::buffer_cast<void*>(*buf));
            delete buf;
        }
    }
};
Why use malloc/free instead of new/delete?

class Pool : enable_shared_from_this<Pool> {
private:
    list<buffer_ptr> buffers; // free to use buffers
List only has exactly the number of nodes to hold the items necessary.  This means nodes are deleted as objects are handed out and nodes are created as objects are return to the pool.  I think using vector would be a better choice since you can reserve memory.  This means as objects come and go the memory size of the container remains the same.
public:
    buffer_ptr allocate(size_t sz) { // minimal size to use
        for(list<buffer_ptr>::iterator i = this->buffers.begin(); i!= this->buffers.end(); ++i)
            if(asio::buffer_size(*i) >= sz) {
                buffer_ptr ret_value = *i;
                this->buffers.erase(i);
                return ret_value;
            }
                           // malloc is NOT checked!!
        return buffer_ptr(new asio::buffer(malloc(sz), sz), // T *t
                          PoolBufferDeleter(shared_from_this())); // D d
    }
In my thinking the pool would only contain objects that are the same.  What I mean is the asio::buffer's would all be the same size.  Nothing wrong with this, I just think if you need different sizes then either have more pools or have the pool be the largest size you need.


    void deallocate(asio::buffer *b) {
        this->buffers.push_front(buffer_ptr(b));
    }
};

Why store shared_ptr's in the list?  The asio::buffer's can be created in the constructor and destroyed in the destructor.  This would prevent memory leaks.  Since the deallocate expects a raw asio::buffer it would be easier to store the raw pointer.  What am I missing?

I like the thought of using the asio::buffer directly instead of a std::vector<unsigned char>(1500).  I do need to overlay a structure on the first 50 bytes or so to create a header.  I know how to do this with the std::vector but how would I accomplish this with the asio::buffer?

Ryan

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net