SingletonThreadLocal.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright 2016-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <boost/intrusive/list.hpp>
  18. #include <folly/ScopeGuard.h>
  19. #include <folly/ThreadLocal.h>
  20. #include <folly/detail/Singleton.h>
  21. #include <folly/functional/Invoke.h>
  22. namespace folly {
  23. /// SingletonThreadLocal
  24. ///
  25. /// Useful for a per-thread leaky-singleton model in libraries and applications.
  26. ///
  27. /// By "leaky" it is meant that the T instances held by the instantiation
  28. /// SingletonThreadLocal<T> will survive until their owning thread exits.
  29. /// Therefore, they can safely be used before main() begins and after main()
  30. /// ends, and they can also safely be used in an application that spawns many
  31. /// temporary threads throughout its life.
  32. ///
  33. /// Example:
  34. ///
  35. /// struct UsefulButHasExpensiveCtor {
  36. /// UsefulButHasExpensiveCtor(); // this is expensive
  37. /// Result operator()(Arg arg);
  38. /// };
  39. ///
  40. /// Result useful(Arg arg) {
  41. /// using Useful = UsefulButHasExpensiveCtor;
  42. /// auto& useful = folly::SingletonThreadLocal<Useful>::get();
  43. /// return useful(arg);
  44. /// }
  45. ///
  46. /// As an example use-case, the random generators in <random> are expensive to
  47. /// construct. And their constructors are deterministic, but many cases require
  48. /// that they be randomly seeded. So folly::Random makes good canonical uses of
  49. /// folly::SingletonThreadLocal so that a seed is computed from the secure
  50. /// random device once per thread, and the random generator is constructed with
  51. /// the seed once per thread.
  52. ///
  53. /// Keywords to help people find this class in search:
  54. /// Thread Local Singleton ThreadLocalSingleton
  55. template <
  56. typename T,
  57. typename Tag = detail::DefaultTag,
  58. typename Make = detail::DefaultMake<T>,
  59. typename TLTag = _t<std::conditional<
  60. std::is_same<Tag, detail::DefaultTag>::value,
  61. void,
  62. Tag>>>
  63. class SingletonThreadLocal {
  64. private:
  65. struct Wrapper;
  66. using NodeBase = boost::intrusive::list_base_hook<
  67. boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
  68. struct Node : NodeBase {
  69. Wrapper*& cache;
  70. bool& stale;
  71. Node(Wrapper*& cache_, bool& stale_) : cache(cache_), stale(stale_) {
  72. auto& wrapper = getWrapper();
  73. wrapper.caches.push_front(*this);
  74. cache = &wrapper;
  75. }
  76. ~Node() {
  77. clear();
  78. }
  79. void clear() {
  80. cache = nullptr;
  81. stale = true;
  82. }
  83. };
  84. using List =
  85. boost::intrusive::list<Node, boost::intrusive::constant_time_size<false>>;
  86. struct Wrapper {
  87. template <typename S>
  88. using MakeRet = is_invocable_r<S, Make>;
  89. // keep as first field, to save 1 instr in the fast path
  90. union {
  91. alignas(alignof(T)) unsigned char storage[sizeof(T)];
  92. T object;
  93. };
  94. List caches;
  95. /* implicit */ operator T&() {
  96. return object;
  97. }
  98. // normal make types
  99. template <typename S = T, _t<std::enable_if<MakeRet<S>::value, int>> = 0>
  100. Wrapper() {
  101. (void)new (storage) S(Make{}());
  102. }
  103. // default and special make types for non-move-constructible T, until C++17
  104. template <typename S = T, _t<std::enable_if<!MakeRet<S>::value, int>> = 0>
  105. Wrapper() {
  106. (void)Make{}(storage);
  107. }
  108. ~Wrapper() {
  109. for (auto& node : caches) {
  110. node.clear();
  111. }
  112. caches.clear();
  113. object.~T();
  114. }
  115. };
  116. using WrapperTL = ThreadLocal<Wrapper, TLTag>;
  117. SingletonThreadLocal() = delete;
  118. FOLLY_EXPORT FOLLY_NOINLINE static WrapperTL& getWrapperTL() {
  119. static auto& entry = *detail::createGlobal<WrapperTL, Tag>();
  120. return entry;
  121. }
  122. FOLLY_NOINLINE static Wrapper& getWrapper() {
  123. return *getWrapperTL();
  124. }
  125. #ifdef FOLLY_TLS
  126. FOLLY_NOINLINE static T& getSlow(Wrapper*& cache) {
  127. static thread_local Wrapper** check = &cache;
  128. CHECK_EQ(check, &cache) << "inline function static thread_local merging";
  129. static thread_local bool stale;
  130. static thread_local Node node(cache, stale);
  131. return !stale && node.cache ? *node.cache : getWrapper();
  132. }
  133. #endif
  134. public:
  135. FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& get() {
  136. #ifdef FOLLY_TLS
  137. static thread_local Wrapper* cache;
  138. return FOLLY_LIKELY(!!cache) ? *cache : getSlow(cache);
  139. #else
  140. return getWrapper();
  141. #endif
  142. }
  143. // Must use a unique Tag, takes a lock that is one per Tag
  144. static typename WrapperTL::Accessor accessAllThreads() {
  145. return getWrapperTL().accessAllThreads();
  146. }
  147. };
  148. } // namespace folly
  149. /// FOLLY_DECLARE_REUSED
  150. ///
  151. /// Useful for local variables of container types, where it is desired to avoid
  152. /// the overhead associated with the local variable entering and leaving scope.
  153. /// Rather, where it is desired that the memory be reused between invocations
  154. /// of the same scope in the same thread rather than deallocated and reallocated
  155. /// between invocations of the same scope in the same thread. Note that the
  156. /// container will always be cleared between invocations; it is only the backing
  157. /// memory allocation which is reused.
  158. ///
  159. /// Example:
  160. ///
  161. /// void traverse_perform(int root);
  162. /// template <typename F>
  163. /// void traverse_each_child_r(int root, F const&);
  164. /// void traverse_depthwise(int root) {
  165. /// // preserves some of the memory backing these per-thread data structures
  166. /// FOLLY_DECLARE_REUSED(seen, std::unordered_set<int>);
  167. /// FOLLY_DECLARE_REUSED(work, std::vector<int>);
  168. /// // example algorithm that uses these per-thread data structures
  169. /// work.push_back(root);
  170. /// while (!work.empty()) {
  171. /// root = work.back();
  172. /// work.pop_back();
  173. /// seen.insert(root);
  174. /// traverse_perform(root);
  175. /// traverse_each_child_r(root, [&](int item) {
  176. /// if (!seen.count(item)) {
  177. /// work.push_back(item);
  178. /// }
  179. /// });
  180. /// }
  181. /// }
  182. #define FOLLY_DECLARE_REUSED(name, ...) \
  183. struct __folly_reused_type_##name { \
  184. __VA_ARGS__ object; \
  185. }; \
  186. auto& name = \
  187. ::folly::SingletonThreadLocal<__folly_reused_type_##name>::get().object; \
  188. auto __folly_reused_g_##name = ::folly::makeGuard([&] { name.clear(); })