SingletonThreadLocalTest.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. #include <thread>
  17. #include <unordered_set>
  18. #include <vector>
  19. #include <folly/SingletonThreadLocal.h>
  20. #include <folly/Synchronized.h>
  21. #include <folly/portability/GTest.h>
  22. using namespace folly;
  23. namespace {
  24. static std::atomic<std::size_t> fooCreatedCount{0};
  25. static std::atomic<std::size_t> fooDeletedCount{0};
  26. struct Foo {
  27. Foo() {
  28. ++fooCreatedCount;
  29. }
  30. ~Foo() {
  31. ++fooDeletedCount;
  32. }
  33. };
  34. using FooSingletonTL = SingletonThreadLocal<Foo>;
  35. } // namespace
  36. TEST(SingletonThreadLocalTest, OneSingletonPerThread) {
  37. static constexpr std::size_t targetThreadCount{64};
  38. std::atomic<std::size_t> completedThreadCount{0};
  39. Synchronized<std::unordered_set<Foo*>> fooAddresses{};
  40. std::vector<std::thread> threads{};
  41. auto threadFunction = [&fooAddresses, &completedThreadCount] {
  42. fooAddresses.wlock()->emplace(&FooSingletonTL::get());
  43. ++completedThreadCount;
  44. while (completedThreadCount < targetThreadCount) {
  45. std::this_thread::yield();
  46. }
  47. };
  48. {
  49. for (std::size_t threadCount{0}; threadCount < targetThreadCount;
  50. ++threadCount) {
  51. threads.emplace_back(threadFunction);
  52. }
  53. }
  54. for (auto& thread : threads) {
  55. thread.join();
  56. }
  57. EXPECT_EQ(threads.size(), fooAddresses.rlock()->size());
  58. EXPECT_EQ(threads.size(), fooCreatedCount);
  59. EXPECT_EQ(threads.size(), fooDeletedCount);
  60. }
  61. TEST(SingletonThreadLocalTest, MoveConstructibleMake) {
  62. struct Foo {
  63. int a, b;
  64. Foo(int a_, int b_) : a(a_), b(b_) {}
  65. Foo(Foo&&) = default;
  66. Foo& operator=(Foo&&) = default;
  67. };
  68. struct Tag {};
  69. struct Make {
  70. Foo operator()() const {
  71. return Foo(3, 4);
  72. }
  73. };
  74. auto& single = SingletonThreadLocal<Foo, Tag, Make>::get();
  75. EXPECT_EQ(4, single.b);
  76. }
  77. TEST(SingletonThreadLocalTest, NotMoveConstructibleMake) {
  78. struct Foo {
  79. int a, b;
  80. Foo(int a_, int b_) : a(a_), b(b_) {}
  81. Foo(Foo&&) = delete;
  82. Foo& operator=(Foo&&) = delete;
  83. };
  84. struct Tag {};
  85. struct Make {
  86. Foo* operator()(unsigned char (&buf)[sizeof(Foo)]) const {
  87. return new (buf) Foo(3, 4);
  88. }
  89. };
  90. auto& single = SingletonThreadLocal<Foo, Tag, Make>::get();
  91. EXPECT_EQ(4, single.b);
  92. }
  93. TEST(SingletonThreadLocalTest, AccessAfterFastPathDestruction) {
  94. static std::atomic<int> counter{};
  95. struct Foo {
  96. int i = 3;
  97. };
  98. struct Bar {
  99. ~Bar() {
  100. counter += SingletonThreadLocal<Foo>::get().i;
  101. }
  102. };
  103. auto th = std::thread([] {
  104. SingletonThreadLocal<Bar>::get();
  105. counter += SingletonThreadLocal<Foo>::get().i;
  106. });
  107. th.join();
  108. EXPECT_EQ(6, counter);
  109. }
  110. TEST(ThreadLocal, DependencyTest) {
  111. typedef folly::ThreadLocalPtr<int> Data;
  112. struct mytag {};
  113. typedef SingletonThreadLocal<int> SingletonInt;
  114. struct barstruct {
  115. ~barstruct() {
  116. SingletonInt::get()++;
  117. Data data;
  118. data.reset(new int(0));
  119. }
  120. };
  121. typedef SingletonThreadLocal<barstruct, mytag> BarSingleton;
  122. std::thread([&]() {
  123. Data data;
  124. data.reset(new int(0));
  125. SingletonInt::get();
  126. BarSingleton::get();
  127. })
  128. .join();
  129. }
  130. TEST(SingletonThreadLocalTest, Reused) {
  131. for (auto i = 0u; i < 2u; ++i) {
  132. FOLLY_DECLARE_REUSED(data, std::string);
  133. if (i == 0u) {
  134. data = "hello";
  135. }
  136. EXPECT_EQ(i == 0u ? "hello" : "", data);
  137. }
  138. }