abseil-cpp/absl/synchronization/notification_test.cc
Go to the documentation of this file.
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 
15 #include "absl/synchronization/notification.h"
16 
17 #include <thread> // NOLINT(build/c++11)
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "absl/synchronization/mutex.h"
22 
23 namespace absl {
25 
26 // A thread-safe class that holds a counter.
28  public:
30 
31  void Increment() {
32  MutexLock lock(&mutex_);
33  ++count_;
34  }
35 
36  int Get() const {
37  MutexLock lock(&mutex_);
38  return count_;
39  }
40 
42  MutexLock lock(&mutex_);
43  auto cond = [this, n]() { return count_ >= n; };
45  }
46 
47  private:
48  mutable Mutex mutex_;
49  int count_;
50 };
51 
52 // Runs the |i|'th worker thread for the tests in BasicTests(). Increments the
53 // |ready_counter|, waits on the |notification|, and then increments the
54 // |done_counter|.
55 static void RunWorker(int i, ThreadSafeCounter* ready_counter,
57  ThreadSafeCounter* done_counter) {
58  ready_counter->Increment();
59  notification->WaitForNotification();
60  done_counter->Increment();
61 }
62 
63 // Tests that the |notification| properly blocks and awakens threads. Assumes
64 // that the |notification| is not yet triggered. If |notify_before_waiting| is
65 // true, the |notification| is triggered before any threads are created, so the
66 // threads never block in WaitForNotification(). Otherwise, the |notification|
67 // is triggered at a later point when most threads are likely to be blocking in
68 // WaitForNotification().
69 static void BasicTests(bool notify_before_waiting, Notification* notification) {
70  EXPECT_FALSE(notification->HasBeenNotified());
72  notification->WaitForNotificationWithTimeout(absl::Milliseconds(0)));
73  EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
74 
75  const absl::Duration delay = absl::Milliseconds(50);
76  const absl::Time start = absl::Now();
77  EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
78  const absl::Duration elapsed = absl::Now() - start;
79 
80  // Allow for a slight early return, to account for quality of implementation
81  // issues on various platforms.
82  const absl::Duration slop = absl::Microseconds(200);
83  EXPECT_LE(delay - slop, elapsed)
84  << "WaitForNotificationWithTimeout returned " << delay - elapsed
85  << " early (with " << slop << " slop), start time was " << start;
86 
87  ThreadSafeCounter ready_counter;
88  ThreadSafeCounter done_counter;
89 
90  if (notify_before_waiting) {
91  notification->Notify();
92  }
93 
94  // Create a bunch of threads that increment the |done_counter| after being
95  // notified.
96  const int kNumThreads = 10;
97  std::vector<std::thread> workers;
98  for (int i = 0; i < kNumThreads; ++i) {
99  workers.push_back(std::thread(&RunWorker, i, &ready_counter, notification,
100  &done_counter));
101  }
102 
103  if (!notify_before_waiting) {
104  ready_counter.WaitUntilGreaterOrEqual(kNumThreads);
105 
106  // Workers have not been notified yet, so the |done_counter| should be
107  // unmodified.
108  EXPECT_EQ(0, done_counter.Get());
109 
110  notification->Notify();
111  }
112 
113  // After notifying and then joining the workers, both counters should be
114  // fully incremented.
115  notification->WaitForNotification(); // should exit immediately
116  EXPECT_TRUE(notification->HasBeenNotified());
117  EXPECT_TRUE(notification->WaitForNotificationWithTimeout(absl::Seconds(0)));
118  EXPECT_TRUE(notification->WaitForNotificationWithDeadline(absl::Now()));
119  for (std::thread& worker : workers) {
120  worker.join();
121  }
122  EXPECT_EQ(kNumThreads, ready_counter.Get());
123  EXPECT_EQ(kNumThreads, done_counter.Get());
124 }
125 
126 TEST(NotificationTest, SanityTest) {
127  Notification local_notification1, local_notification2;
128  BasicTests(false, &local_notification1);
129  BasicTests(true, &local_notification2);
130 }
131 
133 } // namespace absl
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
absl::Time
Definition: third_party/abseil-cpp/absl/time/time.h:642
absl::Mutex
Definition: abseil-cpp/absl/synchronization/mutex.h:131
absl::TEST
TEST(NotificationTest, SanityTest)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:126
EXPECT_LE
#define EXPECT_LE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2030
absl::Mutex::Await
void Await(const Condition &cond)
Definition: abseil-cpp/absl/synchronization/mutex.cc:1548
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
absl::Notification
Definition: abseil-cpp/absl/synchronization/notification.h:66
benchmark::Condition
std::condition_variable Condition
Definition: benchmark/src/mutex.h:69
absl::Milliseconds
constexpr Duration Milliseconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:415
absl::MutexLock
Definition: abseil-cpp/absl/synchronization/mutex.h:525
start
static uint64_t start
Definition: benchmark-pound.c:74
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::Microseconds
constexpr Duration Microseconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:411
worker
Definition: worker.py:1
cond
static uv_cond_t cond
Definition: threadpool.c:33
absl::Duration
Definition: third_party/abseil-cpp/absl/time/time.h:159
absl::ThreadSafeCounter
Definition: abseil-cpp/absl/synchronization/notification_test.cc:27
absl::BasicTests
static void BasicTests(bool notify_before_waiting, Notification *notification)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:69
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::RunWorker
static void RunWorker(int i, ThreadSafeCounter *ready_counter, Notification *notification, ThreadSafeCounter *done_counter)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:55
absl::Seconds
constexpr Duration Seconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:419
absl::Now
ABSL_NAMESPACE_BEGIN Time Now()
Definition: abseil-cpp/absl/time/clock.cc:39
notification
Definition: alts_tsi_handshaker_test.cc:76
absl::ThreadSafeCounter::ThreadSafeCounter
ThreadSafeCounter()
Definition: abseil-cpp/absl/synchronization/notification_test.cc:29
kNumThreads
const int kNumThreads
Definition: thread_stress_test.cc:46
absl::ThreadSafeCounter::Increment
void Increment()
Definition: abseil-cpp/absl/synchronization/notification_test.cc:31
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
absl::ThreadSafeCounter::count_
int count_
Definition: abseil-cpp/absl/synchronization/notification_test.cc:49
workers
struct child_worker * workers
absl::ThreadSafeCounter::Get
int Get() const
Definition: abseil-cpp/absl/synchronization/notification_test.cc:36
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::ThreadSafeCounter::mutex_
Mutex mutex_
Definition: abseil-cpp/absl/synchronization/notification_test.cc:48
absl::ThreadSafeCounter::WaitUntilGreaterOrEqual
void WaitUntilGreaterOrEqual(int n)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:41
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:32