10#ifndef EIGEN_CXX11_THREADPOOL_THREAD_LOCAL_H
11#define EIGEN_CXX11_THREADPOOL_THREAD_LOCAL_H
13#ifdef EIGEN_AVOID_THREAD_LOCAL
15#ifdef EIGEN_THREAD_LOCAL
16#undef EIGEN_THREAD_LOCAL
21#if EIGEN_MAX_CPP_VER >= 11 && \
22 ((EIGEN_COMP_GNUC && EIGEN_GNUC_AT_LEAST(4, 8)) || \
23 __has_feature(cxx_thread_local) || \
24 (EIGEN_COMP_MSVC >= 1900) )
25#define EIGEN_THREAD_LOCAL static thread_local
32#include <Availability.h>
33#include <TargetConditionals.h>
37#if defined(__apple_build_version__) && \
38 ((__apple_build_version__ < 8000042) || \
39 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0))
42#undef EIGEN_THREAD_LOCAL
44#elif defined(__ANDROID__) && EIGEN_COMP_CLANG
53#if __has_include(<android/ndk-version.h>)
54#include <android/ndk-version.h>
56#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
57 defined(__NDK_MINOR__) && \
58 ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
59#undef EIGEN_THREAD_LOCAL
69struct ThreadLocalNoOpInitialize {
70 void operator()(T&)
const {}
74struct ThreadLocalNoOpRelease {
75 void operator()(T&)
const {}
113 typename Initialize = internal::ThreadLocalNoOpInitialize<T>,
114 typename Release = internal::ThreadLocalNoOpRelease<T>>
117 static_assert(std::is_default_constructible<T>::value,
118 "ThreadLocal data type must be default constructible");
121 explicit ThreadLocal(
int capacity)
122 : ThreadLocal(capacity, internal::ThreadLocalNoOpInitialize<T>(),
123 internal::ThreadLocalNoOpRelease<T>()) {}
125 ThreadLocal(
int capacity, Initialize initialize)
126 : ThreadLocal(capacity, std::move(initialize),
127 internal::ThreadLocalNoOpRelease<T>()) {}
129 ThreadLocal(
int capacity, Initialize initialize, Release release)
130 : initialize_(std::move(initialize)),
131 release_(std::move(release)),
136 eigen_assert(capacity_ >= 0);
137 data_.resize(capacity_);
138 for (
int i = 0; i < capacity_; ++i) {
139 ptr_.emplace_back(
nullptr);
144 std::thread::id this_thread = std::this_thread::get_id();
145 if (capacity_ == 0)
return SpilledLocal(this_thread);
147 std::size_t h = std::hash<std::thread::id>()(this_thread);
148 const int start_idx = h % capacity_;
159 while (ptr_[idx].load() !=
nullptr) {
160 ThreadIdAndValue& record = *(ptr_[idx].load());
161 if (record.thread_id == this_thread)
return record.value;
164 if (idx >= capacity_) idx -= capacity_;
165 if (idx == start_idx)
break;
172 if (filled_records_.load() >= capacity_)
return SpilledLocal(this_thread);
178 int insertion_index =
179 filled_records_.fetch_add(1, std::memory_order_relaxed);
180 if (insertion_index >= capacity_)
return SpilledLocal(this_thread);
184 data_[insertion_index].thread_id = this_thread;
185 initialize_(data_[insertion_index].value);
188 ThreadIdAndValue* inserted = &data_[insertion_index];
191 ThreadIdAndValue* empty =
nullptr;
197 const int insertion_idx = idx;
202 while (ptr_[idx].load() !=
nullptr) {
204 if (idx >= capacity_) idx -= capacity_;
207 eigen_assert(idx != insertion_idx);
211 }
while (!ptr_[idx].compare_exchange_weak(empty, inserted));
213 return inserted->value;
217 void ForEach(std::function<
void(std::thread::id, T&)> f) {
220 for (
auto& ptr : ptr_) {
221 ThreadIdAndValue* record = ptr.load();
222 if (record ==
nullptr)
continue;
223 f(record->thread_id, record->value);
227 if (filled_records_.load(std::memory_order_relaxed) < capacity_)
return;
230 std::unique_lock<std::mutex> lock(mu_);
231 for (
auto& kv : per_thread_map_) {
232 f(kv.first, kv.second);
240 for (
auto& ptr : ptr_) {
241 ThreadIdAndValue* record = ptr.load();
242 if (record ==
nullptr)
continue;
243 release_(record->value);
247 if (filled_records_.load(std::memory_order_relaxed) < capacity_)
return;
250 std::unique_lock<std::mutex> lock(mu_);
251 for (
auto& kv : per_thread_map_) {
257 struct ThreadIdAndValue {
258 std::thread::id thread_id;
263 T& SpilledLocal(std::thread::id this_thread) {
264 std::unique_lock<std::mutex> lock(mu_);
266 auto it = per_thread_map_.find(this_thread);
267 if (it == per_thread_map_.end()) {
268 auto result = per_thread_map_.emplace(this_thread, T());
269 eigen_assert(result.second);
270 initialize_((*result.first).second);
271 return (*result.first).second;
277 Initialize initialize_;
283 MaxSizeVector<ThreadIdAndValue> data_;
287 MaxSizeVector<std::atomic<ThreadIdAndValue*>> ptr_;
290 std::atomic<int> filled_records_;
296 std::unordered_map<std::thread::id, T> per_thread_map_;
Namespace containing all symbols from the Eigen library.