jeudi 27 avril 2017

Custom thread local STL allocator with Boost pool allocator

We have a huge legacy code base which is multithreaded and uses vectors extensively. To cut down the time spent in dynamic memory allocation, we are moving to a pools. The plan is to use Boost small vector with a custom allocator. The custom allocator will create a thread local pool per each container type. I have implemented a custom allocator based on the above idea and tested it. For some reason, the code falls in an infinite pattern inside find_prev method in Boost simple segregated storage. There are lots of places where there is a nesting of containers, like vector>> etc. Is this the right way of defining allocator ??

template<typename T, typename allocatorType>
class customAllocator
{
    public:
        static thread_local allocatorType *_allocator;
        typedef T value_type;
        typedef allocatorType allocator_Type;
        template <class X> struct rebind
        {
            typedef customAllocator<X, allocatorType> other;
        };
        customAllocator()
        {
            _allocator = new allocatorType;
            assert(_allocator);
            return;
        }
        ~customAllocator()
        {
            delete _allocator;
            _allocator = nullptr;
            return;
        }
        template<class X, class Y> customAllocator(const customAllocator<X, Y>& other)
        {
            _allocator = other._allocator;
            return;
        }
        template<class X, class Y> customAllocator(customAllocator<X, Y>&& other)
        {
            _allocator = other._allocator;
            other._allocator = nullptr;
            return;
        }
        template<class X, class Y> customAllocator& operator=(const customAllocator<X, Y>& other)
        {
            _allocator = other._allocator;
            return *this;
        }
        template<class X, class Y> customAllocator& operator=(customAllocator<X, Y>&& other)
        {
            _allocator = other._allocator;
            other._allocator = nullptr;
            return *this;
        }
        T* allocate(size_t n)
        {
            return _allocator->allocate(n * sizeof(T));
        }
        void deallocate(T* ptr, size_t n)
        {
            _allocator->deallocate(ptr, n);
            return;
        }
        template<class X, class Y> bool operator==(const customAllocator<X, Y>& other) const noexcept
        { return (*this._allocator == other.allocator);  }
        template<class X, class Y> bool operator!=(const customAllocator<X, Y>& other) const noexcept
        { return !(*this._allocator == other._allocator); }
};
template <typename T1, typename T2>
thread_local T2 *customAllocator<T1, T2>::_allocator = nullptr;

using smallVector = boost::container::small_vector<
T,
    DEFAULT_SMALL_VECTOR_LENGTH,
    customAllocator<T,
    boost::pool_allocator<
    T,
    boost::default_user_allocator_new_delete,
    boost::details::pool::null_mutex,
    2,
    4
    >>>;

Aucun commentaire:

Enregistrer un commentaire