-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSharedLocker.mpp
More file actions
85 lines (69 loc) · 2.44 KB
/
SharedLocker.mpp
File metadata and controls
85 lines (69 loc) · 2.44 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
73
74
75
76
77
78
79
80
81
82
83
84
85
export module CppUtils.Thread.SharedLocker;
import std;
import CppUtils.Thread.UniqueLocker;
export namespace CppUtils::Thread
{
/*
Classe RAII permet des accès multiples à une valeur en lecture seule.
Cette classe ne contient pas la valeur, seulement une référence vers celle-ci.
*/
template<class T>
class ReadOnlyAccessor final
{
public:
inline explicit ReadOnlyAccessor(std::shared_mutex& mutex, const T& value):
m_lockGuard{mutex},
m_value{std::cref(value)}
{}
[[nodiscard]] inline auto value(this auto&& self) noexcept -> decltype(auto)
{
return self.m_value.get();
}
[[nodiscard]] inline auto operator->(this auto&& self) noexcept -> const T*
{
return std::addressof(self.value());
}
[[nodiscard]] inline auto operator*(this auto&& self) noexcept -> decltype(auto)
{
return self.value();
}
[[nodiscard]] inline auto getLockGuard() const& noexcept -> auto&
{
return m_lockGuard;
}
private:
mutable std::shared_lock<std::shared_mutex> m_lockGuard;
std::reference_wrapper<const T> m_value;
};
template<class T>
ReadOnlyAccessor(std::shared_mutex&, const T&) -> ReadOnlyAccessor<T>;
/*
Classe conçue pour encapsuler une ressource avec son mutex, garantissant que l'accès à la ressource passe obligatoirement par un Accessor qui verrouille le mutex (principe de "Monitor Object").
En plus de la protection RAII apportée par std::shared_lock, permettant de libérer le mutex si une exception survient dans le scope du verrou,
cette approche permet à un getter de retourner la valeur protégée en l'accompagnant de son verrouillage (contenus dans un Accessor), assurant ainsi que la ressource est toujours accédée de manière sécurisée.
Cela apporte une sécurité accrue en empêchant structurellement les accès non verrouillés et rend l'intention explicite sur le caractère partagé de l'objet.
*/
template<class T>
class SharedLocker final
{
public:
inline explicit SharedLocker(auto&&... args):
m_value{std::forward<decltype(args)>(args)...}
{}
[[nodiscard]] inline auto uniqueAccess() -> Accessor<T, std::shared_mutex>
{
return Accessor{m_mutex, m_value};
}
[[nodiscard]] inline auto sharedAccess() const -> ReadOnlyAccessor<T>
{
return ReadOnlyAccessor{m_mutex, m_value};
}
private:
mutable std::shared_mutex m_mutex;
T m_value;
template<class... Lockers>
friend struct MultipleAccessor;
};
template<class T>
SharedLocker(T) -> SharedLocker<T>;
}