Repository navigation
Expand file tree
/
Copy pathLockFreeObjectPool.h
More file actions
105 lines (89 loc) · 2.89 KB
/
Copy pathLockFreeObjectPool.h
File metadata and controls
105 lines (89 loc) · 2.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#pragma once
#include <atomic>
#include <memory>
#include <cassert>
// ABA 문제 완화를 위한 태그 포인터 구조체
template <typename T>
struct alignas(16) TaggedPointer
{
T* ptr;
uint64_t tag;
};
template <typename T>
class LockFreeObjectPool
{
private:
struct Node
{
T data;
TaggedPointer<Node> next;
};
std::atomic<TaggedPointer<Node>> m_pFreeList;
std::atomic<size_t> m_availableCount;
public:
LockFreeObjectPool() : m_availableCount(0)
{
m_pFreeList.store(TaggedPointer<Node>{nullptr, 0});
}
~LockFreeObjectPool()
{
TaggedPointer<Node> current = m_pFreeList.load(std::memory_order_relaxed);
while (current.ptr != nullptr)
{
Node* next = current.ptr->next.ptr;
delete current.ptr;
current.ptr = next;
}
}
// Lock 없이 Pool에서 객체를 가져오거나 새로 생성
std::shared_ptr<T> Alloc()
{
TaggedPointer<Node> head = m_pFreeList.load(std::memory_order_acquire);
while (head.ptr != nullptr)
{
TaggedPointer<Node> nextHead = head.ptr->next;
nextHead.tag = head.tag + 1;
if (m_pFreeList.compare_exchange_weak(head, nextHead,
std::memory_order_release,
std::memory_order_relaxed))
{
m_availableCount.fetch_sub(1, std::memory_order_relaxed);
// std::enable_shared_from_this의 weak_ptr 상태를 리셋하기 위해 Placement New 호출
T* ptr = &head.ptr->data;
ptr->~T();
new (ptr) T();
// shared_ptr의 커스텀 삭제자를 지정하여, delete 대신 Free로 반환되게 함
return std::shared_ptr<T>(ptr, [this, node = head.ptr](T* p)
{
this->Free(node);
});
}
}
// Pool이 비어 있다면 바로 생성
Node* newNode = new Node();
return std::shared_ptr<T>(&newNode->data, [this, node = newNode](T* ptr) {
this->Free(node);
});
}
// 사용이 끝난 객체를 락 없이 풀에 반환
void Free(Node* node)
{
assert(node != nullptr);
TaggedPointer<Node> head = m_pFreeList.load(std::memory_order_relaxed);
TaggedPointer<Node> newHead;
newHead.ptr = node;
do
{
newHead.tag = head.tag + 1;
node->next = head;
}
while (!m_pFreeList.compare_exchange_weak(head, newHead,
std::memory_order_release,
std::memory_order_relaxed));
m_availableCount.fetch_add(1, std::memory_order_relaxed);
}
size_t GetAvailableCount() const
{
return m_availableCount.load(std::memory_order_relaxed);
}
};