| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 | // Copyright 2017 The Abseil Authors.//// 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////      https://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 "absl/base/call_once.h"#include <thread>#include <vector>#include "gtest/gtest.h"#include "absl/base/attributes.h"#include "absl/base/const_init.h"#include "absl/base/thread_annotations.h"#include "absl/synchronization/mutex.h"namespace absl {ABSL_NAMESPACE_BEGINnamespace {absl::once_flag once;ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);int running_thread_count ABSL_GUARDED_BY(counters_mu) = 0;int call_once_invoke_count ABSL_GUARDED_BY(counters_mu) = 0;int call_once_finished_count ABSL_GUARDED_BY(counters_mu) = 0;int call_once_return_count ABSL_GUARDED_BY(counters_mu) = 0;bool done_blocking ABSL_GUARDED_BY(counters_mu) = false;// Function to be called from absl::call_once.  Waits for a notification.void WaitAndIncrement() {  counters_mu.Lock();  ++call_once_invoke_count;  counters_mu.Unlock();  counters_mu.LockWhen(Condition(&done_blocking));  ++call_once_finished_count;  counters_mu.Unlock();}void ThreadBody() {  counters_mu.Lock();  ++running_thread_count;  counters_mu.Unlock();  absl::call_once(once, WaitAndIncrement);  counters_mu.Lock();  ++call_once_return_count;  counters_mu.Unlock();}// Returns true if all threads are set up for the test.bool ThreadsAreSetup(void*) ABSL_EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {  // All ten threads must be running, and WaitAndIncrement should be blocked.  return running_thread_count == 10 && call_once_invoke_count == 1;}TEST(CallOnceTest, ExecutionCount) {  std::vector<std::thread> threads;  // Start 10 threads all calling call_once on the same once_flag.  for (int i = 0; i < 10; ++i) {    threads.emplace_back(ThreadBody);  }  // Wait until all ten threads have started, and WaitAndIncrement has been  // invoked.  counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));  // WaitAndIncrement should have been invoked by exactly one call_once()  // instance.  That thread should be blocking on a notification, and all other  // call_once instances should be blocking as well.  EXPECT_EQ(call_once_invoke_count, 1);  EXPECT_EQ(call_once_finished_count, 0);  EXPECT_EQ(call_once_return_count, 0);  // Allow WaitAndIncrement to finish executing.  Once it does, the other  // call_once waiters will be unblocked.  done_blocking = true;  counters_mu.Unlock();  for (std::thread& thread : threads) {    thread.join();  }  counters_mu.Lock();  EXPECT_EQ(call_once_invoke_count, 1);  EXPECT_EQ(call_once_finished_count, 1);  EXPECT_EQ(call_once_return_count, 10);  counters_mu.Unlock();}}  // namespaceABSL_NAMESPACE_END}  // namespace absl
 |