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


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:19