call_once_test.cc 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. #include "absl/base/call_once.h"
  15. #include <thread>
  16. #include <vector>
  17. #include "gtest/gtest.h"
  18. #include "absl/base/attributes.h"
  19. #include "absl/base/const_init.h"
  20. #include "absl/base/thread_annotations.h"
  21. #include "absl/synchronization/mutex.h"
  22. namespace absl {
  23. ABSL_NAMESPACE_BEGIN
  24. namespace {
  25. absl::once_flag once;
  26. ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
  27. int running_thread_count ABSL_GUARDED_BY(counters_mu) = 0;
  28. int call_once_invoke_count ABSL_GUARDED_BY(counters_mu) = 0;
  29. int call_once_finished_count ABSL_GUARDED_BY(counters_mu) = 0;
  30. int call_once_return_count ABSL_GUARDED_BY(counters_mu) = 0;
  31. bool done_blocking ABSL_GUARDED_BY(counters_mu) = false;
  32. // Function to be called from absl::call_once. Waits for a notification.
  33. void WaitAndIncrement() {
  34. counters_mu.Lock();
  35. ++call_once_invoke_count;
  36. counters_mu.Unlock();
  37. counters_mu.LockWhen(Condition(&done_blocking));
  38. ++call_once_finished_count;
  39. counters_mu.Unlock();
  40. }
  41. void ThreadBody() {
  42. counters_mu.Lock();
  43. ++running_thread_count;
  44. counters_mu.Unlock();
  45. absl::call_once(once, WaitAndIncrement);
  46. counters_mu.Lock();
  47. ++call_once_return_count;
  48. counters_mu.Unlock();
  49. }
  50. // Returns true if all threads are set up for the test.
  51. bool ThreadsAreSetup(void*) ABSL_EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
  52. // All ten threads must be running, and WaitAndIncrement should be blocked.
  53. return running_thread_count == 10 && call_once_invoke_count == 1;
  54. }
  55. TEST(CallOnceTest, ExecutionCount) {
  56. std::vector<std::thread> threads;
  57. // Start 10 threads all calling call_once on the same once_flag.
  58. for (int i = 0; i < 10; ++i) {
  59. threads.emplace_back(ThreadBody);
  60. }
  61. // Wait until all ten threads have started, and WaitAndIncrement has been
  62. // invoked.
  63. counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
  64. // WaitAndIncrement should have been invoked by exactly one call_once()
  65. // instance. That thread should be blocking on a notification, and all other
  66. // call_once instances should be blocking as well.
  67. EXPECT_EQ(call_once_invoke_count, 1);
  68. EXPECT_EQ(call_once_finished_count, 0);
  69. EXPECT_EQ(call_once_return_count, 0);
  70. // Allow WaitAndIncrement to finish executing. Once it does, the other
  71. // call_once waiters will be unblocked.
  72. done_blocking = true;
  73. counters_mu.Unlock();
  74. for (std::thread& thread : threads) {
  75. thread.join();
  76. }
  77. counters_mu.Lock();
  78. EXPECT_EQ(call_once_invoke_count, 1);
  79. EXPECT_EQ(call_once_finished_count, 1);
  80. EXPECT_EQ(call_once_return_count, 10);
  81. counters_mu.Unlock();
  82. }
  83. } // namespace
  84. ABSL_NAMESPACE_END
  85. } // namespace absl