aboutsummaryrefslogtreecommitdiffstats
path: root/vespamalloc/src/tests/allocfree/queue.h
blob: 95e4117ff9a56208bd36fe9d5733ba2921ac25b4 (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <vespa/vespalib/util/guard.h>
#include <queue>
#include <condition_variable>


namespace vespalib {

template <typename T>
class Queue {
private:
    std::queue<T> _q;
    std::mutex    _lock;
    std::condition_variable _cond;
    int           _waitRead;
    int           _waitWrite;
    uint32_t      _maxSize;
    bool          _closed;
    T             _nil;
    Queue(const Queue &);
    Queue &operator=(const Queue &);
public:
    Queue(const T &nil, uint32_t maxSize);
    ~Queue();
    void enqueue(const T &entry);
    void close();
    T dequeue();
};

template <typename T>
Queue<T>::Queue(const T &nil, uint32_t maxSize) :
    _q(),
    _lock(),
    _cond(),
    _waitRead(0),
    _waitWrite(0),
    _maxSize(maxSize),
    _closed(false),
    _nil(nil)
{
}

template <typename T>
Queue<T>::~Queue() = default;

template <typename T>
void Queue<T>::enqueue(const T &entry) {
    std::unique_lock guard(_lock);
    while (_q.size() >= _maxSize) {
        CounterGuard cntGuard(_waitWrite);
        _cond.wait(guard);
    }
    _q.push(entry);
    if (_waitRead > 0) {
        _cond.notify_one();
    }
}
template <typename T>
void Queue<T>::close() {
    std::unique_lock guard(_lock);
    _closed = true;
    if (_waitRead > 0) {
        _cond.notify_one();
    }
}
template <typename T>
T Queue<T>::dequeue() {
    std::unique_lock guard(_lock);
    while (_q.empty() && !_closed) {
        CounterGuard cntGuard(_waitRead);
        _cond.wait(guard);
    }
    if (_q.empty()) {
        return _nil;
    }
    T tmp = _q.front();
    _q.pop();
    if (_waitWrite > 0) {
        _cond.notify_one();
    }
    return tmp;
}

}