Boost logo

Boost Users :

Subject: Re: [Boost-users] Object pools?
From: Igore Dmit. (trueorca_at_[hidden])
Date: 2010-02-18 13:44:09


2010/2/18 Ryan McConnehey <mccorywork_at_[hidden]>

> I like your concept for deallocating the object that pool handed out. I
> am using a private static class within pool to provide the function to the
> shared_ptr destructor. This allowed the object to be delete if the pool was
> destroyed but causes a bottleneck for other pools of the same type.
>

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?

> I have two questions. One, shouldn't the PoolObjectDeleter should be a
> template class?

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?

> Two, why is the PoolObjectDeleter passed a shared_ptr<void>? It seems the
> pool_mem is to help with reference counting to determine if the pool is
> destroyed. Yet, I thought the enable_shared_from_this took care of the
> reference counting with the pool.lock().

In my sample pool_mem is malloc'ed objects data bodies memory, it would
cause undefined behavior if accessed after "free". To avoid that shared_ptr
is passed to PoolObjectDeleter. To determine if the pool is destroyed
weak_ptr<Pool> is used.

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;
        }
    }
};

class Pool : enable_shared_from_this<Pool> {
private:
    list<buffer_ptr> buffers; // free to use buffers
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
    }

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

Deleter holds a weak_ptr to pool, so it can determine pool state. It's alive
- pass buffer to it, destroy otherwise.



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