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 | // ----------------------------------------------------------------------------- |
16 | // notification.h |
17 | // ----------------------------------------------------------------------------- |
18 | // |
19 | // This header file defines a `Notification` abstraction, which allows threads |
20 | // to receive notification of a single occurrence of a single event. |
21 | // |
22 | // The `Notification` object maintains a private boolean "notified" state that |
23 | // transitions to `true` at most once. The `Notification` class provides the |
24 | // following primary member functions: |
25 | // * `HasBeenNotified() `to query its state |
26 | // * `WaitForNotification*()` to have threads wait until the "notified" state |
27 | // is `true`. |
28 | // * `Notify()` to set the notification's "notified" state to `true` and |
29 | // notify all waiting threads that the event has occurred. |
30 | // This method may only be called once. |
31 | // |
32 | // Note that while `Notify()` may only be called once, it is perfectly valid to |
33 | // call any of the `WaitForNotification*()` methods multiple times, from |
34 | // multiple threads -- even after the notification's "notified" state has been |
35 | // set -- in which case those methods will immediately return. |
36 | // |
37 | // Note that the lifetime of a `Notification` requires careful consideration; |
38 | // it might not be safe to destroy a notification after calling `Notify()` since |
39 | // it is still legal for other threads to call `WaitForNotification*()` methods |
40 | // on the notification. However, observers responding to a "notified" state of |
41 | // `true` can safely delete the notification without interfering with the call |
42 | // to `Notify()` in the other thread. |
43 | // |
44 | // Memory ordering: For any threads X and Y, if X calls `Notify()`, then any |
45 | // action taken by X before it calls `Notify()` is visible to thread Y after: |
46 | // * Y returns from `WaitForNotification()`, or |
47 | // * Y receives a `true` return value from either `HasBeenNotified()` or |
48 | // `WaitForNotificationWithTimeout()`. |
49 | |
50 | #ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_ |
51 | #define ABSL_SYNCHRONIZATION_NOTIFICATION_H_ |
52 | |
53 | #include <atomic> |
54 | |
55 | #include "absl/base/macros.h" |
56 | #include "absl/synchronization/mutex.h" |
57 | #include "absl/time/time.h" |
58 | |
59 | namespace absl { |
60 | |
61 | // ----------------------------------------------------------------------------- |
62 | // Notification |
63 | // ----------------------------------------------------------------------------- |
64 | class Notification { |
65 | public: |
66 | // Initializes the "notified" state to unnotified. |
67 | Notification() : notified_yet_(false) {} |
68 | explicit Notification(bool prenotify) : notified_yet_(prenotify) {} |
69 | Notification(const Notification&) = delete; |
70 | Notification& operator=(const Notification&) = delete; |
71 | ~Notification(); |
72 | |
73 | // Notification::HasBeenNotified() |
74 | // |
75 | // Returns the value of the notification's internal "notified" state. |
76 | bool HasBeenNotified() const; |
77 | |
78 | // Notification::WaitForNotification() |
79 | // |
80 | // Blocks the calling thread until the notification's "notified" state is |
81 | // `true`. Note that if `Notify()` has been previously called on this |
82 | // notification, this function will immediately return. |
83 | void WaitForNotification() const; |
84 | |
85 | // Notification::WaitForNotificationWithTimeout() |
86 | // |
87 | // Blocks until either the notification's "notified" state is `true` (which |
88 | // may occur immediately) or the timeout has elapsed, returning the value of |
89 | // its "notified" state in either case. |
90 | bool WaitForNotificationWithTimeout(absl::Duration timeout) const; |
91 | |
92 | // Notification::WaitForNotificationWithDeadline() |
93 | // |
94 | // Blocks until either the notification's "notified" state is `true` (which |
95 | // may occur immediately) or the deadline has expired, returning the value of |
96 | // its "notified" state in either case. |
97 | bool WaitForNotificationWithDeadline(absl::Time deadline) const; |
98 | |
99 | // Notification::Notify() |
100 | // |
101 | // Sets the "notified" state of this notification to `true` and wakes waiting |
102 | // threads. Note: do not call `Notify()` multiple times on the same |
103 | // `Notification`; calling `Notify()` more than once on the same notification |
104 | // results in undefined behavior. |
105 | void Notify(); |
106 | |
107 | private: |
108 | mutable Mutex mutex_; |
109 | std::atomic<bool> notified_yet_; // written under mutex_ |
110 | }; |
111 | |
112 | } // namespace absl |
113 | |
114 | #endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_ |
115 | |