Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
kcenon::thread::detail::global_reclamation_manager Class Reference

Global manager for orphaned nodes from terminated threads. More...

#include <hazard_pointer.h>

Collaboration diagram for kcenon::thread::detail::global_reclamation_manager:
Collaboration graph

Public Member Functions

void add_orphaned_nodes (retire_node *head, size_t count)
 Add a list of retired nodes to the global orphanage.
 
size_t reclaim (const std::vector< void * > &protected_ptrs)
 Reclaim orphaned nodes that are no longer protected.
 
size_t get_orphaned_count () const
 Get statistics.
 

Static Public Member Functions

static global_reclamation_managerinstance ()
 

Private Member Functions

 global_reclamation_manager ()=default
 

Private Attributes

std::atomic< retire_node * > head_ {nullptr}
 
std::atomic< size_t > count_ {0}
 

Detailed Description

Global manager for orphaned nodes from terminated threads.

Definition at line 82 of file hazard_pointer.h.

Constructor & Destructor Documentation

◆ global_reclamation_manager()

kcenon::thread::detail::global_reclamation_manager::global_reclamation_manager ( )
privatedefault

Member Function Documentation

◆ add_orphaned_nodes()

void kcenon::thread::detail::global_reclamation_manager::add_orphaned_nodes ( retire_node * head,
size_t count )

Add a list of retired nodes to the global orphanage.

Parameters
headHead of the linked list of retired nodes
countNumber of nodes in the list

Definition at line 153 of file hazard_pointer.cpp.

153 {
154 if (!head)
155 return;
156
157 // Find tail of the new list
158 retire_node* tail = head;
159 while (tail->next) {
160 tail = tail->next;
161 }
162
163 // Atomically prepend to the global list
164 // Use acq_rel: acquire to see the current list, release to publish
165 // the new nodes so that reclaim() sees them
166 retire_node* old_head = head_.load(std::memory_order_acquire);
167 do {
168 tail->next = old_head;
169 } while (!head_.compare_exchange_weak(old_head, head, std::memory_order_acq_rel,
170 std::memory_order_relaxed));
171
172 count_.fetch_add(count, std::memory_order_relaxed);
173}

References count_, head_, and kcenon::thread::detail::retire_node::next.

Referenced by reclaim(), and kcenon::thread::hazard_pointer_domain< T >::thread_retire_list::reclaim_all().

Here is the caller graph for this function:

◆ get_orphaned_count()

size_t kcenon::thread::detail::global_reclamation_manager::get_orphaned_count ( ) const

Get statistics.

Definition at line 233 of file hazard_pointer.cpp.

233 {
234 return count_.load(std::memory_order_relaxed);
235}

References count_.

◆ instance()

global_reclamation_manager & kcenon::thread::detail::global_reclamation_manager::instance ( )
static

Definition at line 148 of file hazard_pointer.cpp.

148 {
149 static global_reclamation_manager manager;
150 return manager;
151}

Referenced by kcenon::thread::hazard_pointer_domain< T >::reclaim(), and kcenon::thread::hazard_pointer_domain< T >::thread_retire_list::reclaim_all().

Here is the caller graph for this function:

◆ reclaim()

size_t kcenon::thread::detail::global_reclamation_manager::reclaim ( const std::vector< void * > & protected_ptrs)

Reclaim orphaned nodes that are no longer protected.

Parameters
protected_ptrsList of currently protected pointers
Returns
Number of nodes reclaimed

Definition at line 175 of file hazard_pointer.cpp.

175 {
176 // Take the entire list to process
177 // Use acq_rel: acquire to see all node data, release to publish
178 // the nullptr so concurrent add_orphaned_nodes sees it
179 retire_node* curr = head_.exchange(nullptr, std::memory_order_acq_rel);
180 if (!curr)
181 return 0;
182
183 size_t reclaimed = 0;
184 retire_node* keep_head = nullptr;
185 retire_node* keep_tail = nullptr;
186 size_t keep_count = 0;
187
188 while (curr) {
189 retire_node* next = curr->next;
190 bool is_protected = false;
191
192 // Check if protected
193 // Binary search since protected_ptrs is sorted
194 if (std::binary_search(protected_ptrs.begin(), protected_ptrs.end(), curr->ptr)) {
195 is_protected = true;
196 }
197
198 if (!is_protected) {
199 // Safe to delete
200 curr->deleter(curr->ptr);
201 delete curr;
202 ++reclaimed;
203 } else {
204 // Keep node
205 if (!keep_head) {
206 keep_head = curr;
207 keep_tail = curr;
208 } else {
209 keep_tail->next = curr;
210 keep_tail = curr;
211 }
212 curr->next = nullptr;
213 ++keep_count;
214 }
215
216 curr = next;
217 }
218
219 // Subtract reclaimed count (not kept, since kept nodes will be re-added
220 // via add_orphaned_nodes which increments count_ itself)
221 // We need to subtract the total taken (reclaimed + keep_count) because
222 // add_orphaned_nodes will add keep_count back
223 count_.fetch_sub(reclaimed + keep_count, std::memory_order_relaxed);
224
225 // Add back kept nodes (this will add keep_count to count_)
226 if (keep_head) {
227 add_orphaned_nodes(keep_head, keep_count);
228 }
229
230 return reclaimed;
231}
void add_orphaned_nodes(retire_node *head, size_t count)
Add a list of retired nodes to the global orphanage.

References add_orphaned_nodes(), count_, kcenon::thread::detail::retire_node::deleter, head_, kcenon::thread::detail::retire_node::next, and kcenon::thread::detail::retire_node::ptr.

Referenced by kcenon::thread::hazard_pointer_domain< T >::reclaim().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ count_

std::atomic<size_t> kcenon::thread::detail::global_reclamation_manager::count_ {0}
private

Definition at line 103 of file hazard_pointer.h.

103{0};

Referenced by add_orphaned_nodes(), get_orphaned_count(), and reclaim().

◆ head_

std::atomic<retire_node*> kcenon::thread::detail::global_reclamation_manager::head_ {nullptr}
private

Definition at line 102 of file hazard_pointer.h.

102{nullptr};

Referenced by add_orphaned_nodes(), and reclaim().


The documentation for this class was generated from the following files: