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