Test for folly::SingletonThreadLocal
authorPhil Willoughby <philwill@fb.com>
Wed, 14 Sep 2016 08:53:09 +0000 (01:53 -0700)
committerFacebook Github Bot <facebook-github-bot-bot@fb.com>
Wed, 14 Sep 2016 09:08:30 +0000 (02:08 -0700)
Summary: Validates that we create a distinct singleton for each thread and that each such singleton is destroyed at its owning-thread's exit.

Reviewed By: yfeldblum

Differential Revision: D3849146

fbshipit-source-id: af878b32ecfc6c82b866d7a805e1385d74a8a5f5

folly/test/Makefile.am
folly/test/SingletonThreadLocalTest.cpp [new file with mode: 0644]

index 0ee3e1ff5c50e76647ff18e00f2f41ae8c70466d..a227287a0d524b9636343894d79f1795ef8d10ba 100644 (file)
@@ -309,4 +309,8 @@ partial_test_SOURCES = PartialTest.cpp
 partial_test_LDADD = libfollytestmain.la
 TESTS += partial_test
 
+singleton_thread_local_test_SOURCES = SingletonThreadLocalTest.cpp
+singleton_thread_local_test_LDADD = libfollytestmain.la
+TESTS += singleton_thread_local_test
+
 check_PROGRAMS += $(TESTS)
diff --git a/folly/test/SingletonThreadLocalTest.cpp b/folly/test/SingletonThreadLocalTest.cpp
new file mode 100644 (file)
index 0000000..5b32918
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+#include <unordered_set>
+#include <vector>
+
+#include <folly/SingletonThreadLocal.h>
+#include <folly/Synchronized.h>
+
+#include <gtest/gtest.h>
+
+using namespace folly;
+
+namespace {
+static std::atomic<std::size_t> fooCreatedCount{0};
+static std::atomic<std::size_t> fooDeletedCount{0};
+struct Foo {
+  Foo() {
+    ++fooCreatedCount;
+  }
+  ~Foo() {
+    ++fooDeletedCount;
+  }
+};
+using FooSingletonTL = SingletonThreadLocal<Foo>;
+FooSingletonTL theFooSingleton;
+}
+
+TEST(SingletonThreadLocalTest, OneSingletonPerThread) {
+  const std::size_t targetThreadCount{64};
+  std::atomic<std::size_t> completedThreadCount{0};
+  Synchronized<std::unordered_set<Foo*>> fooAddresses{};
+  std::vector<std::thread> threads{};
+  auto threadFunction =
+      [&fooAddresses, targetThreadCount, &completedThreadCount] {
+        fooAddresses.wlock()->emplace(&FooSingletonTL::get());
+        ++completedThreadCount;
+        while (completedThreadCount < targetThreadCount) {
+          std::this_thread::yield();
+        }
+      };
+  {
+    for (std::size_t threadCount{0}; threadCount < targetThreadCount;
+         ++threadCount) {
+      threads.emplace_back(threadFunction);
+    }
+  }
+  for (auto& thread : threads) {
+    thread.join();
+  }
+  EXPECT_EQ(threads.size(), fooAddresses.rlock()->size());
+  EXPECT_EQ(threads.size(), fooCreatedCount);
+  EXPECT_EQ(threads.size(), fooDeletedCount);
+}