@@ -19,6 +19,18 @@ constexpr int CACHELINE_BYTES = 128;
1919constexpr int CACHELINE_BYTES = 64 ;
2020#endif
2121
22+ constexpr int _min (int a, int b) { return a > b ? b : a; }
23+
24+ // / calculate the needed padding to separate two members E1 and E2 by at least CACHELINE_BYTES
25+ template <typename E1 , typename E2 , typename ... T> constexpr std::size_t padding () {
26+ return CACHELINE_BYTES -
27+ _min (sizeof (std::tuple<E1 , T..., E2 >) - sizeof (E1 ) - sizeof (E2 ), CACHELINE_BYTES - 1 );
28+ }
29+
30+ template <typename E1 , typename E2 , typename ... T> struct Padding {
31+ const char pad[padding<E1 , E2 , T...>()]{0 };
32+ };
33+
2234/* *
2335 * A thread-safe producer/consumer queue of unread samples.
2436 *
@@ -159,24 +171,35 @@ class consumer_queue {
159171 return ++x == wrap_at_ ? 0 : x;
160172 }
161173
162- // / optional consumer registry
163- send_buffer_p registry_;
174+ // / current read position
175+ std::atomic<std::size_t > read_idx_{0 };
176+ // / condition for waiting with timeout
177+ std::condition_variable cv_;
164178 // / the sample buffer
165179 item_t *buffer_;
180+
181+ // / padding to ensure read_idx_ and write_idx_ don't share a cacheline
182+ Padding<std::size_t , std::size_t , std::condition_variable, void *> pad;
183+
184+ // / current write position
185+ std::atomic<std::size_t > write_idx_{0 };
166186 // / max number of elements in the queue
167187 const std::size_t size_;
168188 // / threshold at which to wrap read/write indices
169189 const std::size_t wrap_at_;
170- // whether we have performed a sync on the data stored by the constructor
171- alignas (CACHELINE_BYTES) std::atomic<bool > done_sync_;
172- // / current write position
173- alignas (CACHELINE_BYTES) std::atomic<std::size_t > write_idx_;
174- // / current read position
175- alignas (CACHELINE_BYTES) std::atomic<std::size_t > read_idx_;
176190 // / for use with the condition variable
177191 std::mutex mut_;
178- // / condition for waiting with timeout
179- std::condition_variable cv_;
192+
193+ // / optional consumer registry
194+ send_buffer_p registry_;
195+
196+ // / padding to ensure write_ix_ and done_sync_ don't share a cacheline
197+ #if UINTPTR_MAX <= 0xFFFFFFFF
198+ Padding<std::size_t , bool , std::size_t , std::size_t , std::mutex, send_buffer_p> pad2;
199+ #endif
200+
201+ // / whether we have performed a sync on the data stored by the constructor
202+ std::atomic<bool > done_sync_{false };
180203};
181204
182205} // namespace lsl
0 commit comments