3535
3636namespace slick {
3737
38+ /* *
39+ * @brief A lock-free multi-producer multi-consumer queue with optional shared memory support.
40+ *
41+ * This queue allows a multiple producer thread to write data and a multiple consumer thread to read data concurrently without locks.
42+ * It can optionally use shared memory for inter-process communication.
43+ *
44+ * @tparam T The type of elements stored in the queue.
45+ */
3846template <typename T>
3947class SlickQueue {
4048 struct slot {
@@ -61,6 +69,15 @@ class SlickQueue {
6169#endif
6270
6371public:
72+ /* *
73+ * @brief Construct a new SlickQueue object
74+ *
75+ * @param size The size of the queue, must be a power of 2.
76+ * @param shm_name The name of the shared memory segment. If nullptr, the queue will use local memory.
77+ *
78+ * @throws std::runtime_error if shared memory allocation fails.
79+ * @throws std::invalid_argument if size is not a power of 2.
80+ */
6481 SlickQueue (uint32_t size, const char * const shm_name = nullptr )
6582 : size_(size)
6683 , buffered_size_(size + 1024 ) // add some buffer at the end
@@ -75,13 +92,15 @@ class SlickQueue {
7592 if (shm_name) {
7693 allocate_shm_data (shm_name, false );
7794 }
78-
79- // if (own_) {
80- // // invalidate first slot
81- // control_[0].data_index.store(-1, std::memory_order_relaxed);
82- // }
8395 }
8496
97+ /* *
98+ * @brief Open an existing SlickQueue in shared memory
99+ *
100+ * @param shm_name The name of the shared memory segment.
101+ *
102+ * @throws std::runtime_error if shared memory allocation fails or the segment does not exist.
103+ */
85104 SlickQueue (const char * const shm_name)
86105 : own_(false )
87106 , use_shm_(true )
@@ -124,32 +143,75 @@ class SlickQueue {
124143 }
125144 }
126145
146+ /* *
147+ * @brief Check if the queue owns the memory buffer
148+ * @return true if the queue owns the memory buffer, false otherwise
149+ */
127150 bool own_buffer () const noexcept { return own_; }
151+
152+ /* *
153+ * @brief Check if the queue uses shared memory
154+ * @return true if the queue uses shared memory, false otherwise
155+ */
128156 bool use_shm () const noexcept { return use_shm_; }
129- constexpr uint32_t size () const noexcept { return mask_ + 1 ; }
130157
158+ /* *
159+ * @brief Get the size of the queue
160+ * @return Size of the queue
161+ */
162+ constexpr uint32_t size () const noexcept { return size_; }
163+
164+ /* *
165+ * @brief Get the initial reading index, which is 0 if the queue is newly created or the current writing index if opened existing
166+ * @return Initial reading index
167+ */
131168 uint64_t initial_reading_index () const noexcept {
132169 return reserved_->load (std::memory_order_relaxed);
133170 }
134171
172+ /* *
173+ * @brief Reserve space in the queue for writing
174+ * @param n Number of slots to reserve, default is 1
175+ * @return The starting index of the reserved space
176+ */
135177 uint64_t reserve (uint32_t n = 1 ) noexcept {
136178 return reserved_->fetch_add (n, std::memory_order_acq_rel);
137179 }
138180
181+ /* *
182+ * @brief Access the reserved space for writing
183+ * @param index The index returned by reserve()
184+ * @return Pointer to the reserved space
185+ */
139186 T* operator [] (uint64_t index) noexcept {
140187 return &data_[index & mask_];
141188 }
142189
190+ /* *
191+ * @brief Access the reserved space for writing (const version)
192+ * @param index The index returned by reserve()
193+ * @return Pointer to the reserved space
194+ */
143195 const T* operator [] (uint64_t index) const noexcept {
144196 return &data_[index & mask_];
145197 }
146198
199+ /* *
200+ * @brief Publish the data written in the reserved space
201+ * @param index The index returned by reserve()
202+ * @param n Number of slots to publish, default is 1
203+ */
147204 void publish (uint64_t index, uint32_t n = 1 ) noexcept {
148205 auto & slot = control_[index & mask_];
149206 slot.size = n;
150207 slot.data_index .store (index, std::memory_order_release);
151208 }
152209
210+ /* *
211+ * @brief Read data from the queue
212+ * @param read_index Reference to the reading index, will be updated to the next index after reading
213+ * @return Pair of pointer to the data and the size of the data, or nullptr and 0 if no data is available
214+ */
153215 std::pair<T*, uint32_t > read (uint64_t & read_index) noexcept {
154216 auto & slot = control_[read_index & mask_];
155217 auto index = slot.data_index .load (std::memory_order_relaxed);
@@ -169,7 +231,8 @@ class SlickQueue {
169231 }
170232
171233 /* *
172- * Read the last published data in the queue
234+ * @brief Read the last published data in the queue
235+ * @return Pointer to the last published data, or nullptr if no data is available
173236 */
174237 T* read_last () noexcept {
175238 auto reserved = reserved_->load (std::memory_order_relaxed);
@@ -192,6 +255,11 @@ class SlickQueue {
192255 return &data_[index & mask_];
193256 }
194257
258+ /* *
259+ * @brief Reset the queue, invalidating all existing data
260+ *
261+ * Note: This function is not thread-safe and should be called when no other threads are accessing the queue.
262+ */
195263 void reset () noexcept {
196264 if (use_shm_) {
197265 control_ = new ((uint8_t *)lpvMem_ + 64 ) slot[buffered_size_];
0 commit comments