From ddb5ca990753e4a6da1fcbadffd12bb022ea2d4f Mon Sep 17 00:00:00 2001 From: Sai Kishor Kothakota Date: Fri, 3 Jan 2025 10:18:56 +0100 Subject: [PATCH] Update condition for bounded push and update documentation --- include/realtime_tools/lock_free_queue.hpp | 60 +++++++++------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/include/realtime_tools/lock_free_queue.hpp b/include/realtime_tools/lock_free_queue.hpp index e9491d01..14a8a0ab 100644 --- a/include/realtime_tools/lock_free_queue.hpp +++ b/include/realtime_tools/lock_free_queue.hpp @@ -104,13 +104,18 @@ struct get_boost_lockfree_queue_capacity class LockFreeQueueBase +/** + * @brief A base class for lock-free queues. + * + * This class provides a base implementation for lock-free queues with various functionalities + * such as pushing, popping, and checking the state of the queue. It supports both single-producer + * single-consumer (SPSC) and multiple-producer multiple-consumer (MPMC) queues. + * + * @tparam DataType The type of data to be stored in the queue. + * @tparam LockFreeContainer The underlying lock-free container type - Typically boost::lockfree::spsc_queue or boost::lockfree::queue with their own template parameters + */ { public: using T = DataType; @@ -190,20 +195,25 @@ class LockFreeQueueBase * @return false If the data could not be pushed * @note This function is enabled only if the queue is a spsc_queue and only if the data type * is convertible to the template type of the queue - * @note To be used in a single threaded applications - * @warning This method might not work as expected if it is used with 2 different threads one - * doing bounded_push and the other doing pop. In this case, the queue is no more a single producer - * single consumer queue. So, the behaviour might not be as expected. + * @note For a SPSC Queue, to be used in single-threaded applications + * @warning For a SPSC Queue, this method might not work as expected when used in multi-threaded applications + * if it is used with two different threads, one doing bounded_push and the other doing pop. In this case, the + * queue is no longer a single producer single consumer queue. So, the behavior might not be as expected. */ - template < - typename U, bool IsSPSCQueue = is_spsc_queue::value, - typename std::enable_if_t = 0> + template [[nodiscard]] std::enable_if_t, bool> bounded_push(const U & data) { - if (!data_queue_.push(data)) { + const auto bounded_push = [this](const U & info) -> bool { + if constexpr (is_spsc_queue::value) { + return data_queue_.push(info); + } else { + return data_queue_.bounded_push(info); + } + }; + if (!bounded_push(data)) { T dummy; data_queue_.pop(dummy); - return data_queue_.push(data); + return bounded_push(data); } return true; } @@ -220,28 +230,6 @@ class LockFreeQueueBase return data_queue_.consume_all([&data](const T & d) { data = d; }) > 0; } - /** - * @brief The bounded_push function pushes the data into the queue and pops the oldest data if the queue is full - * @param data Data to be pushed - * @return true If the data is pushed successfully - * @return false If the data could not be pushed - * @note This function is enabled only if the queue is of multiple producer and multiple consumer - * type and only if the data type is convertible to the template type of the queue - * @note Can be used in a multi threaded applications - */ - template < - typename U, bool IsSPSCQueue = is_spsc_queue::value, - typename std::enable_if_t = 1> - [[nodiscard]] std::enable_if_t, bool> bounded_push(const U & data) - { - if (!data_queue_.bounded_push(data)) { - T dummy; - data_queue_.pop(dummy); - return data_queue_.bounded_push(data); - } - return true; - } - /** * @brief Check if the queue is empty * @return true If the queue is empty