-
Notifications
You must be signed in to change notification settings - Fork 3
/
6.11 线程安全的查询表.cpp
150 lines (129 loc) · 3.74 KB
/
6.11 线程安全的查询表.cpp
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <list>
#include <memory>
#include <utility>
#include <shared_mutex>
#include <algorithm>
#include <vector>
#include <map>
template <typename Key, typename Value, typename Hash = std::hash<Key>>
class threadsafe_lookup_table
{
public:
protected:
private:
class bucket_type
{
public:
Value value_for(const Key &key, const Value &default_value)
{
std::shared_lock<std::shared_mutex> sk(m_smutex);
bucket_iterator const found_entry = find_entry_for(key);
return (found_entry == m_data.end() ? default_value : found_entry->second);
}
Value value_for(const Key &key, const Value &default_value)const
{
std::shared_lock<std::shared_mutex> sk(m_smutex);
typename bucket_data::const_iterator found_entry = find_entry_for(key);
return (found_entry == m_data.end() ? default_value : found_entry->second);
}
void add_or_update_mapping(const Key &key, const Value &value)
{
std::unique_lock<std::shared_mutex> uk(m_smutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry == m_data.end())
{
m_data.push_back(bucket_value(key, value));
}
else
{
found_entry->second = value;
}
}
void remove_mapping(const Key &key)
{
std::unique_lock<std::shared_mutex> uk(m_smutex);
bucket_iterator found_entry = find_entry_for(key);
if (found_entry != m_data.end())
{
m_data.erase(found_entry);
}
}
using bucket_value = std::pair<Key, Value>;
using bucket_data = std::list<bucket_value>;
using bucket_iterator = typename bucket_data::iterator;
bucket_data m_data;
mutable std::shared_mutex m_smutex;
private:
bucket_iterator find_entry_for(const Key& key)
{
return std::find_if(m_data.begin(), m_data.end(), [&](const bucket_value &item) { return item.first == key; });
};
typename bucket_data::const_iterator find_entry_for(const Key& key)const
{
return std::find_if(m_data.begin(), m_data.end(), [&](const bucket_value &item) { return item.first == key; });
}
};
std::vector<std::unique_ptr<bucket_type>> buckets;
Hash hasher;
bucket_type &get_bucket(const Key &key)const
{
std::size_t const bucket_index = hasher(key) % buckets.size();
return *buckets[bucket_index];
}
public:
using key_type = Key;
using mapped_type = Value;
using hash_type = Hash;
threadsafe_lookup_table(unsigned num_buckets = 19, const Hash &hasher_ = Hash())
: buckets(num_buckets), hasher(hasher_)
{
for (size_t index = 0; index < num_buckets; ++index)
{
buckets[index].reset(new bucket_type());
}
}
threadsafe_lookup_table(const threadsafe_lookup_table&) = delete;
threadsafe_lookup_table &operator=(const threadsafe_lookup_table&) = delete;
Value value_for(const Key &key, const Value &default_value = Value())const
{
return get_bucket(key).value_for(key, default_value);
}
void add_for_update_mapping(const Key &key, const Value &value)
{
get_bucket(key).add_or_update_mapping(key, value);
}
void remove_mapping(const Key &key)
{
get_bucket(key).remove_mapping(key);
}
std::map<Key, Value> get_map()const
{
std::vector<std::unique_lock<std::shared_mutex>> vecUKs;
for (size_t index = 0; index < buckets.size(); ++index)
{
vecUKs.push_back(std::unique_lock<std::shared_mutex>(buckets[index]->m_smutex));
}
std::map<Key, Value> res;
for (size_t index = 0; index < buckets.size(); ++index)
{
for (auto it = buckets[index]->m_data.cbegin(); it != buckets[index]->m_data.cend(); ++it)
{
res.insert(*it);
}
}
return res;
}
};
int main()
{
threadsafe_lookup_table<int, int> tlt;
tlt.add_for_update_mapping(1, 2);
tlt.add_for_update_mapping(3, 2);
tlt.value_for(3, 3);
tlt.remove_mapping(3);
tlt.get_map();
const threadsafe_lookup_table<int, int> &tl = tlt;
tl.value_for(1, 2);
tl.get_map();
return EXIT_SUCCESS;
}