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_BEGIN
- namespace {
- 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();
- }
- } // namespace
- ABSL_NAMESPACE_END
- } // namespace absl
|