call_once_test.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/base/call_once.h"
00016 
00017 #include <thread>
00018 #include <vector>
00019 
00020 #include "gtest/gtest.h"
00021 #include "absl/base/attributes.h"
00022 #include "absl/base/const_init.h"
00023 #include "absl/base/thread_annotations.h"
00024 #include "absl/synchronization/mutex.h"
00025 
00026 namespace absl {
00027 namespace {
00028 
00029 absl::once_flag once;
00030 
00031 ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
00032 
00033 int running_thread_count GUARDED_BY(counters_mu) = 0;
00034 int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
00035 int call_once_finished_count GUARDED_BY(counters_mu) = 0;
00036 int call_once_return_count GUARDED_BY(counters_mu) = 0;
00037 bool done_blocking GUARDED_BY(counters_mu) = false;
00038 
00039 // Function to be called from absl::call_once.  Waits for a notification.
00040 void WaitAndIncrement() {
00041   counters_mu.Lock();
00042   ++call_once_invoke_count;
00043   counters_mu.Unlock();
00044 
00045   counters_mu.LockWhen(Condition(&done_blocking));
00046   ++call_once_finished_count;
00047   counters_mu.Unlock();
00048 }
00049 
00050 void ThreadBody() {
00051   counters_mu.Lock();
00052   ++running_thread_count;
00053   counters_mu.Unlock();
00054 
00055   absl::call_once(once, WaitAndIncrement);
00056 
00057   counters_mu.Lock();
00058   ++call_once_return_count;
00059   counters_mu.Unlock();
00060 }
00061 
00062 // Returns true if all threads are set up for the test.
00063 bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
00064   // All ten threads must be running, and WaitAndIncrement should be blocked.
00065   return running_thread_count == 10 && call_once_invoke_count == 1;
00066 }
00067 
00068 TEST(CallOnceTest, ExecutionCount) {
00069   std::vector<std::thread> threads;
00070 
00071   // Start 10 threads all calling call_once on the same once_flag.
00072   for (int i = 0; i < 10; ++i) {
00073     threads.emplace_back(ThreadBody);
00074   }
00075 
00076 
00077   // Wait until all ten threads have started, and WaitAndIncrement has been
00078   // invoked.
00079   counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
00080 
00081   // WaitAndIncrement should have been invoked by exactly one call_once()
00082   // instance.  That thread should be blocking on a notification, and all other
00083   // call_once instances should be blocking as well.
00084   EXPECT_EQ(call_once_invoke_count, 1);
00085   EXPECT_EQ(call_once_finished_count, 0);
00086   EXPECT_EQ(call_once_return_count, 0);
00087 
00088   // Allow WaitAndIncrement to finish executing.  Once it does, the other
00089   // call_once waiters will be unblocked.
00090   done_blocking = true;
00091   counters_mu.Unlock();
00092 
00093   for (std::thread& thread : threads) {
00094     thread.join();
00095   }
00096 
00097   counters_mu.Lock();
00098   EXPECT_EQ(call_once_invoke_count, 1);
00099   EXPECT_EQ(call_once_finished_count, 1);
00100   EXPECT_EQ(call_once_return_count, 10);
00101   counters_mu.Unlock();
00102 }
00103 
00104 }  // namespace
00105 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14