SList(Interlocked Singly Linked List)를 활용하여 Object Pool을 구현해봤다.
Poolable
Object Pool을 통해 관리할 객체들은 Poolable 클래스를 상속받아야 한다.
Poolable 객체는 Object Pool에 의해 관리된다.
operator new와 delete를 오버로딩하여 object pool을 사용한 할당과 해제방식으로 변경했다.
new 연산자에서는 object pool에서 객체를 하나 꺼내오고,
delete 연산자에서는 object pool에 사용한 객체를 넣는다.
Object Pool
Object Pool은 SList를 통해 구현했다.
Push는 리스트에 Poolable 객체를 넣는 메소드다.
InterlockedPushEntrySList 함수를 사용하여 SList에 해당 객체를 집어넣는다.
Pop은 리스트에서 Poolable 객체를 꺼내는 메소드다.
InterlockedPopEntrySList 함수를 사용하여 SList에서 객체를 하나 꺼내온다.
만약, SList에 사용가능한 객체가 하나도 없는경우, _aligned_malloc을 사용하여 새로 할당해준다.
이때 할당되는 객체는 MEMORY_ALLOCATION_ALIGNMENT(16)으로 정렬되어야 한다.
Example Code
#pragma once
#include "Common.h"
/* --------------------------------------------------------
* class: ObjectPool
* Summary: Object Pool using SList
-------------------------------------------------------- */
template<typename TObject>
class ObjectPool
{
public:
ObjectPool();
ObjectPool(const ObjectPool& other) = delete;
ObjectPool(ObjectPool&& other) = delete;
ObjectPool& operator=(const ObjectPool& other) = delete;
ObjectPool& operator=(ObjectPool&& other) = delete;
~ObjectPool() = default;
void Push(TObject* ptr);
TObject* Pop();
private:
SLIST_HEADER m_header;
atomic<int> m_useCount;
atomic<int> m_allocCount;
};
template<typename TObject>
inline ObjectPool<TObject>::ObjectPool()
: m_header()
, m_useCount(0)
, m_allocCount(0)
{
}
template<typename TObject>
inline void ObjectPool<TObject>::Push(TObject* ptr)
{
::InterlockedPushEntrySList(&m_header, static_cast<PSLIST_ENTRY>(ptr));
m_useCount.fetch_sub(1);
}
template<typename TObject>
inline TObject* ObjectPool<TObject>::Pop()
{
TObject* object = static_cast<TObject*>(::InterlockedPopEntrySList(&m_header));
if (object == nullptr)
{
object = reinterpret_cast<TObject*>(::_aligned_malloc(sizeof(TObject), 16));
m_allocCount.fetch_add(1);
}
m_useCount.fetch_add(1);
return object;
}
/* --------------------------------------------------------
* class: Poolable
* Summary: Objects that can be included in a ObjectPool
-------------------------------------------------------- */
template<typename TObject>
class Poolable : public SLIST_ENTRY
{
public:
template<typename... Args>
static void* operator new(size_t objSize, Args&&... args)
{
TObject* object = s_pool.Pop();
if (object == nullptr)
{
HandleError("Poolable::new");
return nullptr;
}
return static_cast<void*>(object);
}
static void operator delete(void* obj)
{
s_pool.Push(static_cast<TObject*>(obj));
}
private:
static ObjectPool<TObject> s_pool;
};
template<typename TObject>
ObjectPool<TObject> Poolable<TObject>::s_pool{};
'Server > Multithreading' 카테고리의 다른 글
[Object Pool] SList를 사용한 Object Pool 구현(1) (0) | 2023.05.25 |
---|