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