Replace LocklessAllocator with new MemoryPool class
MemoryPool maintains a free list of pre-allocated entries stored in a libcds MPMC Queue. In contrast to LocklessAllocator, it's a lot faster, less (and less complex) code to maintain for us and it doesn't fail when it's full.
This commit is contained in:
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* LocklessAllocator.h - allocator with lockless alloc and free
|
||||
*
|
||||
* Copyright (c) 2016 Javier Serrano Polo <javier@jasp.net>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LOCKLESS_ALLOCATOR_H
|
||||
#define LOCKLESS_ALLOCATOR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <stddef.h>
|
||||
|
||||
class LocklessAllocator
|
||||
{
|
||||
public:
|
||||
LocklessAllocator( size_t nmemb, size_t size );
|
||||
virtual ~LocklessAllocator();
|
||||
void * alloc();
|
||||
void free( void * ptr );
|
||||
|
||||
|
||||
private:
|
||||
char * m_pool;
|
||||
size_t m_capacity;
|
||||
size_t m_elementSize;
|
||||
|
||||
std::atomic_int * m_freeState;
|
||||
size_t m_freeStateSets;
|
||||
|
||||
std::atomic_int m_available;
|
||||
std::atomic_int m_startIndex;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
class LocklessAllocatorT : private LocklessAllocator
|
||||
{
|
||||
public:
|
||||
LocklessAllocatorT( size_t nmemb ) :
|
||||
LocklessAllocator( nmemb, sizeof( T ) )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~LocklessAllocatorT()
|
||||
{
|
||||
}
|
||||
|
||||
T * alloc()
|
||||
{
|
||||
return (T *)LocklessAllocator::alloc();
|
||||
}
|
||||
|
||||
void free( T * ptr )
|
||||
{
|
||||
LocklessAllocator::free( ptr );
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifndef LOCKLESS_LIST_H
|
||||
#define LOCKLESS_LIST_H
|
||||
|
||||
#include "LocklessAllocator.h"
|
||||
#include "MemoryPool.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
|
||||
LocklessList( size_t size ) :
|
||||
m_first(nullptr),
|
||||
m_allocator(new LocklessAllocatorT<Element>(size))
|
||||
m_allocator(new MemoryPool<Element>(size))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
void push( T value )
|
||||
{
|
||||
Element * e = m_allocator->alloc();
|
||||
Element * e = m_allocator->allocate();
|
||||
e->value = value;
|
||||
e->next = m_first.load(std::memory_order_relaxed);
|
||||
|
||||
@@ -81,14 +81,13 @@ public:
|
||||
|
||||
void free( Element * e )
|
||||
{
|
||||
m_allocator->free( e );
|
||||
m_allocator->destroy( e );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::atomic<Element*> m_first;
|
||||
LocklessAllocatorT<Element> * m_allocator;
|
||||
|
||||
MemoryPool<Element> * m_allocator;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
82
include/MemoryPool.h
Normal file
82
include/MemoryPool.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* MemoryPool.h
|
||||
*
|
||||
* Copyright (c) 2018 Lukas W <lukaswhl/at/gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This file is licensed under the MIT license. See LICENSE.MIT.txt file in the
|
||||
* project root for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
class _MemoryPool_Private;
|
||||
|
||||
class _MemoryPool_Base
|
||||
{
|
||||
public:
|
||||
_MemoryPool_Base(size_t size, size_t nmemb);
|
||||
virtual ~_MemoryPool_Base();
|
||||
void * allocate();
|
||||
void * allocate_bounded();
|
||||
void deallocate(void * ptr);
|
||||
|
||||
private:
|
||||
const std::unique_ptr<_MemoryPool_Private> _imp;
|
||||
};
|
||||
|
||||
/// Thread-safe, lockless memory pool. Only supports allocate(n) with n=1. When
|
||||
/// the pool is exhausted, MmAllocator is used.
|
||||
template<typename T>
|
||||
class MemoryPool : private _MemoryPool_Base
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
template<class U> struct rebind { typedef MemoryPool<U> other; };
|
||||
|
||||
MemoryPool(size_t nmemb) : _MemoryPool_Base(sizeof(T), nmemb) {}
|
||||
|
||||
T * allocate(size_t n = 1)
|
||||
{
|
||||
if (n != 1) { throw std::bad_alloc{}; }
|
||||
return reinterpret_cast<T*>(_MemoryPool_Base::allocate());
|
||||
}
|
||||
|
||||
T * allocate_bounded()
|
||||
{
|
||||
return reinterpret_cast<T*>(_MemoryPool_Base::allocate_bounded());
|
||||
}
|
||||
|
||||
void deallocate(T * ptr, size_t n = 1)
|
||||
{
|
||||
_MemoryPool_Base::deallocate(ptr);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
T * construct(Args&&... args)
|
||||
{
|
||||
T* buffer = allocate();
|
||||
return ::new ((void*)buffer) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<class... Args >
|
||||
T * construct_bounded(Args&&... args)
|
||||
{
|
||||
T* buffer = allocate_bounded();
|
||||
if (buffer) {
|
||||
::new ((void*)buffer) T(std::forward<Args>(args)...);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void destroy(T* ptr)
|
||||
{
|
||||
ptr->~T();
|
||||
deallocate(ptr);
|
||||
}
|
||||
} ;
|
||||
15
include/libcds.h
Normal file
15
include/libcds.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "NiftyCounter.h"
|
||||
|
||||
namespace _cdslib
|
||||
{
|
||||
void init();
|
||||
void deinit();
|
||||
void thread_init();
|
||||
void thread_deinit();
|
||||
|
||||
static NiftyCounter<init, deinit> _counter;
|
||||
static NiftyCounterTL<thread_init, thread_init> _thread_counter;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user