PLCnext API Documentation 26.6.0.38
SharedData.hxx
1#pragma once
3#include "Arp/System/Core/TypeName.hxx"
4#include "Arp/System/Commons/Ipc/SharedMemory.hpp"
5#include "Arp/System/Commons/Threading/Thread.hpp"
6#include "boost/interprocess/allocators/allocator.hpp"
7#include "boost/interprocess/containers/string.hpp"
8#include "boost/interprocess/containers/vector.hpp"
9#include "boost/interprocess/containers/list.hpp"
10#include "boost/interprocess/containers/map.hpp"
11#include "boost/interprocess/containers/set.hpp"
12#include <algorithm> // using std::replace
13#include <new> // using std::new(p)
14
15#ifdef ARP_PLATFORM_LINUX
16 #include <pthread.h>
17#endif
18
19namespace Arp { namespace System { namespace Commons { namespace Ipc
20{
21
22// This class uses CRTP (Curiously recurring template pattern) to implement an own SharedData singleton
23// for each derived class.
24// For CRTP see: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
25template<class Derived>
26class SharedData : public SharedMemory
27{
28public: // usings
29 using Base = SharedMemory;
30 using DerivedType = Derived;
31 using SharedMemory = boost::interprocess::managed_shared_memory;
32 using SegmentManager = SharedMemory::segment_manager;
33 using SharedMemoryPermission = boost::interprocess::permissions;
34
35 // define pointer type
36 template <class T>
37 using Ptr = boost::interprocess::offset_ptr<T>;
38
39 // define const pointer type
40 template <class T>
41 using ConstPtr = boost::interprocess::offset_ptr<const T>;
42
43protected: // construction/destruction
44 SharedData(void); // opens an existing instance, throws if not exist
45 SharedData(size_t memorySize); // creates an non-existing instance, throws if yet exists
46
47public: // nested type Allocator
48 template <class T>
49 class Allocator : public boost::interprocess::allocator<T, SegmentManager>
50 {
51 public: // typedef
52 using AllocatorBase = boost::interprocess::allocator<T, SegmentManager>;
53 using segment_manager = SegmentManager;
54 using value_type = typename AllocatorBase::value_type;
55 using pointer = typename AllocatorBase::pointer;
56 using const_pointer = typename AllocatorBase::const_pointer;
57 using void_pointer = typename AllocatorBase::void_pointer;
58 using reference = typename AllocatorBase::reference;
59 using const_reference = typename AllocatorBase::const_reference;
60 using size_type = typename AllocatorBase::size_type;
61 using difference_type = typename AllocatorBase::difference_type;
62 using version = typename AllocatorBase::version;
63
64 public: // construction
65 Allocator(void) : AllocatorBase(DerivedType::GetInstance().sharedMemoryImpl.get_segment_manager()) {}
66 Allocator(const Allocator& arg) = default;
67 Allocator(Allocator&& arg)noexcept = default;
68 Allocator& operator=(const Allocator& arg)noexcept = default;
69 Allocator& operator=(Allocator&& arg)noexcept = default;
70 ~Allocator(void) = default;
71
72 public: // meta-programming
73 template<class U>
74 struct rebind
75 {
76 using other = Allocator<U>;
77 };
78 };
79 // declare Allocator as friend of this class
80 template<class T> friend class Allocator;
81
82public: // nested type Mutex
83#ifdef ARP_PLATFORM_LINUX
84 class Mutex
85 {
86 public: // construction
87 Mutex(void)
88 {
89 pthread_mutexattr_t attr;
90 pthread_mutexattr_init(&attr);
91
92 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
93 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
94 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
95
96 pthread_mutex_init(&this->mutex, &attr);
97
98 pthread_mutexattr_destroy(&attr);
99 }
100 Mutex(const Mutex&) = delete;
101 Mutex(Mutex&&) = delete;
102 Mutex& operator=(const Mutex&) = delete;
103 Mutex& operator=(Mutex&&) = delete;
104 ~Mutex(void)
105 {
106 pthread_mutex_destroy(&this->mutex);
107 }
108
109 public: // Operations
110 void Lock(void)
111 {
112 pthread_mutex_lock(&this->mutex);
113 }
114 bool TryLock(void)
115 {
116 return (pthread_mutex_trylock(&this->mutex) == 0);
117 }
118 void Unlock(void)
119 {
120 pthread_mutex_unlock(&this->mutex);
121 }
122
123 private: // fields
124 pthread_mutex_t mutex;
125 };
126#else
127 class Mutex
128 {
129 public: // construction
130 Mutex(void) = default;
131 ~Mutex(void) = default;
132
133 public: // Operations
134 void Lock(void)
135 {
136 this->mutex.lock();
137 }
138 bool TryLock(void)
139 {
140 return this->mutex.try_lock();
141 }
142 void Unlock(void)
143 {
144 this->mutex.unlock();
145 }
146
147 private: // fields
148 boost::interprocess::interprocess_mutex mutex;
149 };
150#endif
151
153 {
154 public: // construction
155 NullMutex(void) = default;
156 ~NullMutex(void) = default;
157
158 public: // Operations
159 void Lock(void) {}
160 void Unlock(void) {}
161 };
162
163public: // nested type ScopedLock
164 template <class TMutex>
166 {
167 public: // construction
168 ScopedLock(TMutex& mutex): pMutex(&mutex)
169 {
170 this->pMutex->Lock();
171 }
172 ScopedLock(const ScopedLock&) = delete;
173 ScopedLock(ScopedLock&&) = delete;
174 ScopedLock& operator=(const ScopedLock&) = delete;
175 ScopedLock& operator=(ScopedLock&&) = delete;
176
177 ~ScopedLock(void)
178 {
179 if (this->pMutex)
180 {
181 this->pMutex->Unlock();
182 }
183 }
184
185 private: // fields
186 TMutex* pMutex;
187 };
188
189public: // usings on nested types
190 // define shared string type
191 using String = boost::interprocess::basic_string<char, std::char_traits<char>, Allocator<char>>;
192 // define shared vector type
193 template <class T>
194 using vector = boost::interprocess::vector<T, Allocator<T>>;
195 // define shared list type
196 template <class T>
197 using list = boost::interprocess::list<T, Allocator<T>>;
198 // define shared map type
199 template <class TKey, class T, class TCompare = std::less<TKey>>
200 using map = boost::interprocess::map<TKey, T, TCompare, Allocator<std::pair<const TKey, T>>>;
201 // define shared set type
202 template <class T, class TCompare = std::less<T>>
203 using set = boost::interprocess::set<T, TCompare, Allocator<T>>;
204};
205
207// inline methods of class SharedData<Derived>
208template<class Derived>
210 : Base(TypeName<DerivedType>().GetSafeName())
211{
212}
213
214template<class Derived>
215inline SharedData<Derived>::SharedData(size_t memorySize)
216 : Base(TypeName<DerivedType>().GetSafeName(), memorySize)
217{
218}
219
221// inline methods of nested class SharedData<Derived>::Allocator<T>
222
223
224}}}} // end of namespace Arp::System::Commons::Ipc
This (meta programming) class provides the C++ type-name of the as template argument passed type.
Definition: TypeName.hxx:20
Definition: SharedData.hxx:128
Definition: SharedData.hxx:27
SharedMemoryImpl sharedMemoryImpl
Actual implementation of the shared memory functionality.
Definition: SharedMemory.hpp:72
Mutual exclusion object to prevent data from concurrent modifications.
Definition: Mutex.hpp:27
Root namespace for the PLCnext API