#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;
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();
}
bool ThreadsAreSetup(void*) ABSL_EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
return running_thread_count == 10 && call_once_invoke_count == 1;
}
TEST(CallOnceTest, ExecutionCount) {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(ThreadBody);
}
counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
EXPECT_EQ(call_once_invoke_count, 1);
EXPECT_EQ(call_once_finished_count, 0);
EXPECT_EQ(call_once_return_count, 0);
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();
}
}
ABSL_NAMESPACE_END
}