Blender V5.0
BLI_enumerable_thread_specific.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#ifdef WITH_TBB
12/* Quiet top level deprecation message, unrelated to API usage here. */
13# if defined(WIN32) && !defined(NOMINMAX)
14/* TBB includes Windows.h which will define min/max macros causing issues
15 * when we try to use std::min and std::max later on. */
16# define NOMINMAX
17# define TBB_MIN_MAX_CLEANUP
18# endif
19# include <tbb/enumerable_thread_specific.h>
20# ifdef WIN32
21/* We cannot keep this defined, since other parts of the code deal with this on their own, leading
22 * to multiple define warnings unless we un-define this, however we can only undefine this if we
23 * were the ones that made the definition earlier. */
24# ifdef TBB_MIN_MAX_CLEANUP
25# undef NOMINMAX
26# endif
27# endif
28#else
29# include <atomic>
30# include <functional>
31
32# include "BLI_map.hh"
33# include "BLI_mutex.hh"
34#endif
35
36#include "BLI_utility_mixins.hh"
37
39
40#ifndef WITH_TBB
42inline std::atomic<int> next_id = 0;
43inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed);
44} // namespace enumerable_thread_specific_utils
45#endif /* !WITH_TBB */
46
53template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
54#ifdef WITH_TBB
55
56 private:
57 tbb::enumerable_thread_specific<T> values_;
58
59 public:
60 using iterator = typename tbb::enumerable_thread_specific<T>::iterator;
61
62 EnumerableThreadSpecific() = default;
63
64 template<typename F> EnumerableThreadSpecific(F initializer) : values_(std::move(initializer)) {}
65
66 T &local()
67 {
68 return values_.local();
69 }
70
72 {
73 return values_.begin();
74 }
75
77 {
78 return values_.end();
79 }
80
81#else /* WITH_TBB */
82
83 private:
84 Mutex mutex_;
85 /* Maps thread ids to their corresponding values. The values are not embedded in the map, so that
86 * their addresses do not change when the map grows. */
88 Vector<std::unique_ptr<T>> owned_values_;
89 std::function<void(void *)> initializer_;
90
91 public:
92 using iterator = typename Map<int, std::reference_wrapper<T>>::MutableValueIterator;
93
94 EnumerableThreadSpecific() : initializer_([](void *buffer) { new (buffer) T(); }) {}
95
96 template<typename F>
98 : initializer_([=](void *buffer) { new (buffer) T(initializer()); })
99 {
100 }
101
103 {
105 std::lock_guard lock{mutex_};
106 return values_.lookup_or_add_cb(thread_id, [&]() {
107 T *value = (T *)::operator new(sizeof(T));
108 initializer_(value);
109 owned_values_.append(std::unique_ptr<T>{value});
110 return std::reference_wrapper<T>{*value};
111 });
112 }
113
115 {
116 return values_.values().begin();
117 }
118
120 {
121 return values_.values().end();
122 }
123
124#endif /* WITH_TBB */
125};
126
127} // namespace blender::threading
volatile int lock
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
typename Map< int, std::reference_wrapper< T > >::MutableValueIterator iterator
#define T
#define F
std::mutex Mutex
Definition BLI_mutex.hh:47