Skip to content

Commit 447e6b7

Browse files
committed
Concurrent map queue and unit test
1 parent ecd6182 commit 447e6b7

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

src/utils/concurrentmapqueue.h

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include <chrono>
2+
#include <condition_variable>
3+
#include <iostream>
4+
#include <map>
5+
#include <mutex>
6+
#include <queue>
7+
#include <string>
8+
#include <thread>
9+
10+
using namespace std;
11+
12+
class Semaphore {
13+
public:
14+
Semaphore(int count_ = 0) : count(count_) {}
15+
16+
inline void notify() {
17+
std::unique_lock<std::mutex> lock(mtx);
18+
count++;
19+
cv.notify_one();
20+
}
21+
inline void wait() {
22+
std::unique_lock<std::mutex> lock(mtx);
23+
while (count == 0) {
24+
cv.wait(lock);
25+
}
26+
count--;
27+
}
28+
29+
private:
30+
std::mutex mtx;
31+
std::condition_variable cv;
32+
int count;
33+
};
34+
35+
template <typename T, typename K> class ConcurrentMapQueue {
36+
private:
37+
map<K, queue<T>> _collection;
38+
map<K, chrono::time_point<chrono::steady_clock>> _timing;
39+
bool canRead(K key);
40+
Semaphore *_semR;
41+
Semaphore *_semW;
42+
void write(K &key, T &value);
43+
T read(K &key);
44+
45+
public:
46+
ConcurrentMapQueue(int max_size);
47+
~ConcurrentMapQueue();
48+
void put(K &key, T &value);
49+
T get(K &key);
50+
vector<K> getKeys();
51+
unsigned long getKeyAge(K &);
52+
};
53+
54+
template <typename T, typename K> ConcurrentMapQueue<T, K>::ConcurrentMapQueue(int max_size) {
55+
_semR = new Semaphore(1);
56+
_semW = new Semaphore(max_size);
57+
}
58+
59+
template <typename T, typename K> ConcurrentMapQueue<T, K>::~ConcurrentMapQueue() {
60+
delete _semR;
61+
delete _semW;
62+
}
63+
64+
template <typename T, typename K> bool ConcurrentMapQueue<T, K>::canRead(K key) { return _collection[key].size() > 0; }
65+
66+
template <typename T, typename K> void ConcurrentMapQueue<T, K>::write(K &key, T &value) {
67+
if (_collection.find(key) == _collection.end()) {
68+
auto first = std::pair<const K, queue<T>>(key, queue<T>());
69+
first.second.push(value);
70+
_collection.insert(first);
71+
_timing.insert(make_pair(key, chrono::steady_clock::now()));
72+
} else {
73+
_collection[key].push(value);
74+
_timing[key] = chrono::steady_clock::now();
75+
}
76+
}
77+
78+
template <typename T, typename K> T ConcurrentMapQueue<T, K>::read(K &key) {
79+
auto value = &_collection[key];
80+
auto el = value->front();
81+
value->pop();
82+
return el;
83+
}
84+
85+
template <typename T, typename K> void ConcurrentMapQueue<T, K>::put(K &key, T &value) {
86+
_semW->wait();
87+
write(key, value);
88+
_semW->notify();
89+
}
90+
91+
template <typename T, typename K> T ConcurrentMapQueue<T, K>::get(K &key) {
92+
_semR->wait();
93+
while (!canRead(key)) {
94+
_semR->wait();
95+
}
96+
97+
auto result = read(key);
98+
_semR->notify();
99+
return result;
100+
}
101+
102+
template <typename T, typename K> vector<K> ConcurrentMapQueue<T, K>::getKeys() {
103+
104+
vector<K> keys;
105+
for (auto const &element : _collection) {
106+
keys.push_back(element.first);
107+
}
108+
return keys;
109+
}
110+
111+
template <typename T, typename K> unsigned long ConcurrentMapQueue<T, K>::getKeyAge(K &key) {
112+
if (_timing.count(key) > 0) {
113+
return chrono::duration_cast<std::chrono::milliseconds>(chrono::steady_clock::now() - _timing[key]).count();
114+
}
115+
return 0;
116+
}

test/concurrentmapqueue_ok.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "../src/utils/concurrentmapqueue.h"
2+
#include <cassert>
3+
4+
using namespace std;
5+
6+
int main(int argc, char *argv[]) {
7+
ConcurrentMapQueue<int, string> mq(10);
8+
9+
string k1("test1");
10+
11+
int i1 = 1, i2 = 2, i3 = 3;
12+
13+
mq.put(k1, i1);
14+
mq.put(k1, i2);
15+
mq.put(k1, i3);
16+
17+
assert(mq.get(k1) == i1);
18+
assert(mq.get(k1) == i2);
19+
assert(mq.get(k1) == i3);
20+
21+
cout << "success" << endl;
22+
23+
return 0;
24+
}

0 commit comments

Comments
 (0)