Blender V4.3
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
5#pragma once
6
7#ifdef WITH_TBB
8/* Quiet top level deprecation message, unrelated to API usage here. */
9# if defined(WIN32) && !defined(NOMINMAX)
10/* TBB includes Windows.h which will define min/max macros causing issues
11 * when we try to use std::min and std::max later on. */
12# define NOMINMAX
13# define TBB_MIN_MAX_CLEANUP
14# endif
15# include <tbb/enumerable_thread_specific.h>
16# ifdef WIN32
17/* We cannot keep this defined, since other parts of the code deal with this on their own, leading
18 * to multiple define warnings unless we un-define this, however we can only undefine this if we
19 * were the ones that made the definition earlier. */
20# ifdef TBB_MIN_MAX_CLEANUP
21# undef NOMINMAX
22# endif
23# endif
24#else
25# include <atomic>
26# include <functional>
27# include <mutex>
28
29# include "BLI_map.hh"
30#endif
31
32#include "BLI_utility_mixins.hh"
33
35
36#ifndef WITH_TBB
37namespace enumerable_thread_specific_utils {
38inline std::atomic<int> next_id = 0;
39inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed);
40} // namespace enumerable_thread_specific_utils
41#endif /* !WITH_TBB */
42
49template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
50#ifdef WITH_TBB
51
52 private:
53 tbb::enumerable_thread_specific<T> values_;
54
55 public:
56 using iterator = typename tbb::enumerable_thread_specific<T>::iterator;
57
58 EnumerableThreadSpecific() = default;
59
60 template<typename F> EnumerableThreadSpecific(F initializer) : values_(std::move(initializer)) {}
61
62 T &local()
63 {
64 return values_.local();
65 }
66
68 {
69 return values_.begin();
70 }
71
73 {
74 return values_.end();
75 }
76
77#else /* WITH_TBB */
78
79 private:
80 std::mutex mutex_;
81 /* Maps thread ids to their corresponding values. The values are not embedded in the map, so that
82 * their addresses do not change when the map grows. */
84 Vector<std::unique_ptr<T>> owned_values_;
85 std::function<void(void *)> initializer_;
86
87 public:
88 using iterator = typename Map<int, std::reference_wrapper<T>>::MutableValueIterator;
89
90 EnumerableThreadSpecific() : initializer_([](void *buffer) { new (buffer) T(); }) {}
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
volatile int lock
void append(const T &value)
typename Map< int, std::reference_wrapper< T > >::MutableValueIterator iterator
#define T