thread_identity_test.cc
Go to the documentation of this file.
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <thread> // NOLINT(build/c++11)
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "absl/base/attributes.h"
23 #include "absl/base/macros.h"
26 
27 namespace absl {
28 namespace base_internal {
29 namespace {
30 
31 // protects num_identities_reused
32 static absl::base_internal::SpinLock map_lock(
34 static int num_identities_reused;
35 
36 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
37 
38 static void TestThreadIdentityCurrent(const void* assert_no_identity) {
39  ThreadIdentity* identity;
40 
41  // We have to test this conditionally, because if the test framework relies
42  // on Abseil, then some previous action may have already allocated an
43  // identity.
44  if (assert_no_identity == kCheckNoIdentity) {
45  identity = CurrentThreadIdentityIfPresent();
46  EXPECT_TRUE(identity == nullptr);
47  }
48 
50  EXPECT_TRUE(identity != nullptr);
51  ThreadIdentity* identity_no_init;
52  identity_no_init = CurrentThreadIdentityIfPresent();
53  EXPECT_TRUE(identity == identity_no_init);
54 
55  // Check that per_thread_synch is correctly aligned.
56  EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
58  EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
59 
61  num_identities_reused++;
62 }
63 
64 TEST(ThreadIdentityTest, BasicIdentityWorks) {
65  // This tests for the main() thread.
66  TestThreadIdentityCurrent(nullptr);
67 }
68 
69 TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
70  // Now try the same basic test with multiple threads being created and
71  // destroyed. This makes sure that:
72  // - New threads are created without a ThreadIdentity.
73  // - We re-allocate ThreadIdentity objects from the free-list.
74  // - If a thread implementation chooses to recycle threads, that
75  // correct re-initialization occurs.
76  static const int kNumLoops = 3;
77  static const int kNumThreads = 400;
78  for (int iter = 0; iter < kNumLoops; iter++) {
79  std::vector<std::thread> threads;
80  for (int i = 0; i < kNumThreads; ++i) {
81  threads.push_back(
82  std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
83  }
84  for (auto& thread : threads) {
85  thread.join();
86  }
87  }
88 
89  // We should have recycled ThreadIdentity objects above; while (external)
90  // library threads allocating their own identities may preclude some
91  // reuse, we should have sufficient repetitions to exclude this.
92  EXPECT_LT(kNumThreads, num_identities_reused);
93 }
94 
95 TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
96  // This test repeatly creates and joins a series of threads, each of
97  // which acquires and releases shared Mutex locks. This verifies
98  // Mutex operations work correctly under a reused
99  // ThreadIdentity. Note that the most likely failure mode of this
100  // test is a crash or deadlock.
101  static const int kNumLoops = 10;
102  static const int kNumThreads = 12;
103  static const int kNumMutexes = 3;
104  static const int kNumLockLoops = 5;
105 
106  Mutex mutexes[kNumMutexes];
107  for (int iter = 0; iter < kNumLoops; ++iter) {
108  std::vector<std::thread> threads;
109  for (int thread = 0; thread < kNumThreads; ++thread) {
110  threads.push_back(std::thread([&]() {
111  for (int l = 0; l < kNumLockLoops; ++l) {
112  for (int m = 0; m < kNumMutexes; ++m) {
113  MutexLock lock(&mutexes[m]);
114  }
115  }
116  }));
117  }
118  for (auto& thread : threads) {
119  thread.join();
120  }
121  }
122 }
123 
124 } // namespace
125 } // namespace base_internal
126 } // namespace absl
TEST(NotificationTest, SanityTest)
base_internal::ThreadIdentity * GetOrCreateCurrentThreadIdentity()
ThreadIdentity * CurrentThreadIdentityIfPresent()
Definition: algorithm.h:29
constexpr int32_t kNumThreads


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:20