blob: be00dad7aa9e37c57587aa1dd9c0d951b20e06c3 (
plain) (
blame)
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
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
#include "time.h"
#include <mutex>
#include <condition_variable>
namespace vespalib {
/**
* A countdown latch helps one or more threads wait for the completion
* of a number of operations performed by other threads. Specifically,
* any thread invoking the await method will block until the countDown
* method has been invoked an appropriate number of times. The
* countdown latch is created with a count. Each invocation of
* countDown will reduce the current count. When the count reaches 0,
* the threads blocked in await will be unblocked. When the count is
* 0, additional invocations of await will not block and additional
* invocations of countDown will have no effect.
**/
class CountDownLatch
{
private:
mutable std::mutex _lock;
std::condition_variable _cond;
uint32_t _count;
CountDownLatch(const CountDownLatch &rhs) = delete;
CountDownLatch(CountDownLatch &&rhs) = delete;
CountDownLatch &operator=(const CountDownLatch &rhs) = delete;
CountDownLatch &operator=(CountDownLatch &&rhs) = delete;
public:
/**
* Create a countdown latch with the given initial count.
*
* @param cnt initial count
**/
CountDownLatch(uint32_t cnt) noexcept : _lock(), _cond(), _count(cnt) {}
/**
* Count down this latch. When the count reaches 0, all threads
* blocked in the await method will be unblocked.
**/
void countDown() {
std::lock_guard guard(_lock);
if (_count != 0) {
--_count;
if (_count == 0) {
_cond.notify_all();
}
}
}
/**
* Wait for this latch to count down to 0. This method will block
* until the countDown method has been invoked enough times to
* reduce the count to 0.
**/
void await() {
std::unique_lock guard(_lock);
_cond.wait(guard, [this]() { return (_count == 0); });
}
/**
* Wait for this latch to count down to 0. This method will block
* until the countDown method has been invoked enough times to
* reduce the count to 0 or the given amount of time has elapsed.
*
* @param maxwait the maximum number of milliseconds to wait
* @return true if the counter reached 0, false if we timed out
**/
bool await(vespalib::duration maxwait) {
std::unique_lock guard(_lock);
return _cond.wait_for(guard, maxwait, [this]() { return (_count == 0); });
}
/**
* Obtain the current count for this latch. This method is mostly
* useful for debugging and testing.
*
* @return current count
**/
[[nodiscard]] uint32_t getCount() const noexcept {
std::lock_guard guard(_lock);
return _count;
}
/**
* Empty. Needs to be virtual to reduce compiler warnings.
**/
virtual ~CountDownLatch();
};
} // namespace vespalib
|