POSIX Shared Memory Data Structures 1.0
High-performance lock-free data structures for inter-process communication
Loading...
Searching...
No Matches
shm_atomic.h
Go to the documentation of this file.
1#pragma once
2#include "posix_shm.h"
3#include "shm_table.h"
4#include <atomic>
5#include <concepts>
6#include <string_view>
7
17template<typename T, typename TableType = shm_table>
18 requires std::is_trivially_copyable_v<T> && std::atomic<T>::is_always_lock_free
20private:
21 std::atomic<T>* atom_ptr{nullptr};
22 const typename TableType::entry* table_entry{nullptr};
23
24 std::atomic<T>* get_atomic_ptr(void* base_addr, size_t offset) {
25 return reinterpret_cast<std::atomic<T>*>(
26 static_cast<char*>(base_addr) + offset
27 );
28 }
29
30public:
31 // STL-compliant type aliases
32 using value_type = T;
33
37 template<typename ShmType>
38 shm_atomic(ShmType& shm, std::string_view name, T initial_value = T{}) {
39 static_assert(std::is_same_v<typename ShmType::table_type, TableType>,
40 "SharedMemory table type must match atomic table type");
41
42 auto* table = static_cast<TableType*>(shm.get_base_addr());
43
44 char name_buf[TableType::MAX_NAME_SIZE]{};
45 size_t copy_len = std::min(name.size(), sizeof(name_buf) - 1);
46 std::copy_n(name.begin(), copy_len, name_buf);
47
48 auto* entry = table->find(name_buf);
49
50 if (entry) {
51 // Open existing atomic
52 if (entry->elem_size != sizeof(std::atomic<T>)) {
53 throw std::runtime_error("Type size mismatch for atomic");
54 }
55 atom_ptr = get_atomic_ptr(shm.get_base_addr(), entry->offset);
56 table_entry = entry;
57 } else {
58 // Create new atomic
59 size_t required_size = sizeof(std::atomic<T>);
60 size_t table_size = sizeof(TableType);
61 size_t current_used = table->get_total_allocated_size();
62
63 size_t offset = table_size + current_used;
64 atom_ptr = get_atomic_ptr(shm.get_base_addr(), offset);
65
66 // Initialize atomic
67 new (atom_ptr) std::atomic<T>(initial_value);
68
69 // Register in table
70 if (!table->add(name_buf, offset, required_size, sizeof(std::atomic<T>), 1)) {
71 throw std::runtime_error("Failed to add atomic to table");
72 }
73 table_entry = table->find(name_buf);
74 }
75 }
76
77 // std::atomic compatible interface
78 [[nodiscard]] bool is_lock_free() const noexcept {
79 return atom_ptr->is_lock_free();
80 }
81
82 static constexpr bool is_always_lock_free = std::atomic<T>::is_always_lock_free;
83
84 void store(T value, std::memory_order order = std::memory_order_seq_cst) noexcept {
85 atom_ptr->store(value, order);
86 }
87
88 [[nodiscard]] T load(std::memory_order order = std::memory_order_seq_cst) const noexcept {
89 return atom_ptr->load(order);
90 }
91
92 [[nodiscard]] T exchange(T value, std::memory_order order = std::memory_order_seq_cst) noexcept {
93 return atom_ptr->exchange(value, order);
94 }
95
96 [[nodiscard]] bool compare_exchange_weak(T& expected, T desired,
97 std::memory_order success = std::memory_order_seq_cst,
98 std::memory_order failure = std::memory_order_seq_cst) noexcept {
99 return atom_ptr->compare_exchange_weak(expected, desired, success, failure);
100 }
101
102 [[nodiscard]] bool compare_exchange_strong(T& expected, T desired,
103 std::memory_order success = std::memory_order_seq_cst,
104 std::memory_order failure = std::memory_order_seq_cst) noexcept {
105 return atom_ptr->compare_exchange_strong(expected, desired, success, failure);
106 }
107
108 // Arithmetic operations (enabled for integral and floating-point types)
109 template<typename U = T>
110 requires std::is_integral_v<U> || std::is_floating_point_v<U>
111 T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
112 return atom_ptr->fetch_add(arg, order);
113 }
114
115 template<typename U = T>
116 requires std::is_integral_v<U> || std::is_floating_point_v<U>
117 T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
118 return atom_ptr->fetch_sub(arg, order);
119 }
120
121 // Bitwise operations (enabled for integral types)
122 template<typename U = T>
123 requires std::is_integral_v<U>
124 T fetch_and(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
125 return atom_ptr->fetch_and(arg, order);
126 }
127
128 template<typename U = T>
129 requires std::is_integral_v<U>
130 T fetch_or(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
131 return atom_ptr->fetch_or(arg, order);
132 }
133
134 template<typename U = T>
135 requires std::is_integral_v<U>
136 T fetch_xor(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept {
137 return atom_ptr->fetch_xor(arg, order);
138 }
139
140 // Operators
141 T operator=(T value) noexcept {
142 store(value);
143 return value;
144 }
145
146 operator T() const noexcept {
147 return load();
148 }
149
150 // Increment/decrement for integral types
151 template<typename U = T>
152 requires std::is_integral_v<U>
153 T operator++() noexcept {
154 return fetch_add(1) + 1;
155 }
156
157 template<typename U = T>
158 requires std::is_integral_v<U>
159 T operator++(int) noexcept {
160 return fetch_add(1);
161 }
162
163 template<typename U = T>
164 requires std::is_integral_v<U>
165 T operator--() noexcept {
166 return fetch_sub(1) - 1;
167 }
168
169 template<typename U = T>
170 requires std::is_integral_v<U>
171 T operator--(int) noexcept {
172 return fetch_sub(1);
173 }
174
175 // Compound assignment operators
176 template<typename U = T>
177 requires std::is_integral_v<U> || std::is_floating_point_v<U>
178 T operator+=(T arg) noexcept {
179 return fetch_add(arg) + arg;
180 }
181
182 template<typename U = T>
183 requires std::is_integral_v<U> || std::is_floating_point_v<U>
184 T operator-=(T arg) noexcept {
185 return fetch_sub(arg) - arg;
186 }
187
188 template<typename U = T>
189 requires std::is_integral_v<U>
190 T operator&=(T arg) noexcept {
191 return fetch_and(arg) & arg;
192 }
193
194 template<typename U = T>
195 requires std::is_integral_v<U>
196 T operator|=(T arg) noexcept {
197 return fetch_or(arg) | arg;
198 }
199
200 template<typename U = T>
201 requires std::is_integral_v<U>
202 T operator^=(T arg) noexcept {
203 return fetch_xor(arg) ^ arg;
204 }
205
206 // Metadata access
207 [[nodiscard]] std::string_view name() const noexcept {
208 return table_entry ? std::string_view(table_entry->name.data()) : std::string_view{};
209 }
210
211 // Wait operations (C++20)
212 void wait(T old, std::memory_order order = std::memory_order_seq_cst) const noexcept {
213 atom_ptr->wait(old, order);
214 }
215
216 void notify_one() noexcept {
217 atom_ptr->notify_one();
218 }
219
220 void notify_all() noexcept {
221 atom_ptr->notify_all();
222 }
223};
224
225// Convenience type aliases for common atomic types
226template<typename TableType = shm_table>
228
229template<typename TableType = shm_table>
231
232template<typename TableType = shm_table>
234
235template<typename TableType = shm_table>
237
238template<typename TableType = shm_table>
240
241template<typename TableType = shm_table>
Shared memory atomic value with auto-discovery.
Definition shm_atomic.h:19
T fetch_sub(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:117
T fetch_add(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:111
T operator-=(T arg) noexcept
Definition shm_atomic.h:184
T operator--(int) noexcept
Definition shm_atomic.h:171
bool is_lock_free() const noexcept
Definition shm_atomic.h:78
void notify_all() noexcept
Definition shm_atomic.h:220
T operator^=(T arg) noexcept
Definition shm_atomic.h:202
T operator++() noexcept
Definition shm_atomic.h:153
T fetch_or(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:130
std::string_view name() const noexcept
Definition shm_atomic.h:207
T exchange(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:92
static constexpr bool is_always_lock_free
Definition shm_atomic.h:82
T operator&=(T arg) noexcept
Definition shm_atomic.h:190
shm_atomic(ShmType &shm, std::string_view name, T initial_value=T{})
Create or open a shared atomic value.
Definition shm_atomic.h:38
bool compare_exchange_strong(T &expected, T desired, std::memory_order success=std::memory_order_seq_cst, std::memory_order failure=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:102
T operator+=(T arg) noexcept
Definition shm_atomic.h:178
bool compare_exchange_weak(T &expected, T desired, std::memory_order success=std::memory_order_seq_cst, std::memory_order failure=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:96
T operator=(T value) noexcept
Definition shm_atomic.h:141
void store(T value, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:84
T fetch_xor(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:136
T fetch_and(T arg, std::memory_order order=std::memory_order_seq_cst) noexcept
Definition shm_atomic.h:124
T load(std::memory_order order=std::memory_order_seq_cst) const noexcept
Definition shm_atomic.h:88
void wait(T old, std::memory_order order=std::memory_order_seq_cst) const noexcept
Definition shm_atomic.h:212
T operator--() noexcept
Definition shm_atomic.h:165
T operator++(int) noexcept
Definition shm_atomic.h:159
void notify_one() noexcept
Definition shm_atomic.h:216
T operator|=(T arg) noexcept
Definition shm_atomic.h:196
Core POSIX shared memory management with automatic reference counting.