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_COMP_GNUC) || __has_feature(cxx_thread_local) || EIGEN_COMP_MSVC)
22#define EIGEN_THREAD_LOCAL static thread_local
29#include <Availability.h>
30#include <TargetConditionals.h>
34#if EIGEN_COMP_CLANGAPPLE && \
35 ((EIGEN_COMP_CLANGAPPLE < 8000042) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0))
38#undef EIGEN_THREAD_LOCAL
40#elif defined(__ANDROID__) && EIGEN_COMP_CLANG
49#if __has_include(<android/ndk-version.h>)
50#include <android/ndk-version.h>
52#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && defined(__NDK_MINOR__) && \
53 ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
54#undef EIGEN_THREAD_LOCAL
61#include "./InternalHeaderCheck.h"
67struct ThreadLocalNoOpInitialize {
68 void operator()(T&)
const {}
72struct ThreadLocalNoOpRelease {
73 void operator()(T&)
const {}
110template <
typename T,
typename Initialize =
internal::ThreadLocalNoOpInitialize<T>,
111 typename Release =
internal::ThreadLocalNoOpRelease<T>>
114 static_assert(std::is_default_constructible<T>::value,
"ThreadLocal data type must be default constructible");
117 explicit ThreadLocal(
int capacity)
118 : ThreadLocal(capacity, internal::ThreadLocalNoOpInitialize<T>(), internal::ThreadLocalNoOpRelease<T>()) {}
120 ThreadLocal(
int capacity, Initialize initialize)
121 : ThreadLocal(capacity, std::move(initialize), internal::ThreadLocalNoOpRelease<T>()) {}
123 ThreadLocal(
int capacity, Initialize initialize, Release release)
124 : initialize_(std::move(initialize)),
125 release_(std::move(release)),
130 eigen_assert(capacity_ >= 0);
131 data_.resize(capacity_);
132 for (
int i = 0; i < capacity_; ++i) {
133 ptr_.emplace_back(
nullptr);
138 std::thread::id this_thread = std::this_thread::get_id();
139 if (capacity_ == 0)
return SpilledLocal(this_thread);
141 std::size_t h = std::hash<std::thread::id>()(this_thread);
142 const int start_idx = h % capacity_;
153 while (ptr_[idx].load() !=
nullptr) {
154 ThreadIdAndValue& record = *(ptr_[idx].load());
155 if (record.thread_id == this_thread)
return record.value;
158 if (idx >= capacity_) idx -= capacity_;
159 if (idx == start_idx)
break;
166 if (filled_records_.load() >= capacity_)
return SpilledLocal(this_thread);
172 int insertion_index = filled_records_.fetch_add(1, std::memory_order_relaxed);
173 if (insertion_index >= capacity_)
return SpilledLocal(this_thread);
177 data_[insertion_index].thread_id = this_thread;
178 initialize_(data_[insertion_index].value);
181 ThreadIdAndValue* inserted = &data_[insertion_index];
184 ThreadIdAndValue* empty =
nullptr;
190 const int insertion_idx = idx;
195 while (ptr_[idx].load() !=
nullptr) {
197 if (idx >= capacity_) idx -= capacity_;
200 eigen_assert(idx != insertion_idx);
204 }
while (!ptr_[idx].compare_exchange_weak(empty, inserted));
206 return inserted->value;
210 void ForEach(std::function<
void(std::thread::id, T&)> f) {
213 for (
auto& ptr : ptr_) {
214 ThreadIdAndValue* record = ptr.load();
215 if (record ==
nullptr)
continue;
216 f(record->thread_id, record->value);
220 if (filled_records_.load(std::memory_order_relaxed) < capacity_)
return;
223 EIGEN_MUTEX_LOCK lock(mu_);
224 for (
auto& kv : per_thread_map_) {
225 f(kv.first, kv.second);
233 for (
auto& ptr : ptr_) {
234 ThreadIdAndValue* record = ptr.load();
235 if (record ==
nullptr)
continue;
236 release_(record->value);
240 if (filled_records_.load(std::memory_order_relaxed) < capacity_)
return;
243 EIGEN_MUTEX_LOCK lock(mu_);
244 for (
auto& kv : per_thread_map_) {
250 struct ThreadIdAndValue {
251 std::thread::id thread_id;
256 T& SpilledLocal(std::thread::id this_thread) {
257 EIGEN_MUTEX_LOCK lock(mu_);
259 auto it = per_thread_map_.find(this_thread);
260 if (it == per_thread_map_.end()) {
261 auto result = per_thread_map_.emplace(this_thread, T());
262 eigen_assert(result.second);
263 initialize_((*result.first).second);
264 return (*result.first).second;
270 Initialize initialize_;
276 MaxSizeVector<ThreadIdAndValue> data_;
280 MaxSizeVector<std::atomic<ThreadIdAndValue*>> ptr_;
283 std::atomic<int> filled_records_;
289 std::unordered_map<std::thread::id, T> per_thread_map_;
Namespace containing all symbols from the Eigen library.
Definition Core:137