-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAtomic.h
More file actions
73 lines (64 loc) · 2.15 KB
/
Atomic.h
File metadata and controls
73 lines (64 loc) · 2.15 KB
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
/*
Copyright [2024] [Yao Yao]
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
http://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.
*/
// The purpose of this is to provide a atomic class that share lock among many objects.
// The most useful case is that when there are many objects, the chance for lock contention
// is low. It would be nice to make each mutex protect multiple objects. When contention is
// low, this should not impact performance and reduce the amount of mutex we need.
#pragma once
#include <shared_mutex>
#include <vector>
class SharedMutexPool
{
public:
static SharedMutexPool& instance() {
static SharedMutexPool pool{8192};
return pool;
}
template <typename Key>
std::shared_mutex& getLock(Key key) {
return std::hash<Key>{}(key) % mLocks.size();
}
private:
explicit SharedMutexPool(size_t nbLocks) :mLocks(nbLocks){};
private:
std::vector<std::shared_mutex> mLocks;
};
template <typename T>
class Atomic
{
public:
template <typename Args...>
Atomic(Args&&... args) : mData{std::forward<Args>(args)...} {}
Atomic(T&& src) : mData{[]()->T{
std::lock_guard<std::shared_mutex> lk{src.getLock()};
return T{std::move(src.mData)};
}()}{}
Atomic(const T& src) : mData{src.load()} {}
T load() const {
std::shared_lock<std::shared_mutex> lk{getLock()};
return mData;
}
void store(T src) {
std::lock_guard<std::shared_mutex> lk{getLock()};
mData = std::move(src);
}
private:
std::uintptr_t key() const {
return reinterpret_cast<std::uintptr_t>(&mData) % alignof(mData);
}
std::shared_mutex& getLock() const {
return SharedMutexPool::instance().getLock(key());
}
private:
T mData;
};