I'm pretty new to the world of lock-free programming and would love some feedback on this code. I have been testing the queue with multiple producers and consumers, and with no unexpected output (yet). Is there anything I could have missed or should improve?
template <typename Type, std::size_t Capacity = 100>
struct concurrent_queue
{
static_assert(Capacity > 2, "not enough room in queue!");
bool try_push(Type const & object) const
{
auto past_writer = writer.load();
auto next_writer = increment(past_writer);
if (next_writer != reader.load())
{
if (writer.compare_exchange_weak(past_writer, next_writer))
{
array[past_writer] = object;
return true;
}
}
return false;
}
bool try_push(Type & object) const
{
auto past_writer = writer.load();
auto next_writer = increment(past_writer);
if (next_writer != reader.load())
{
if (writer.compare_exchange_weak(past_writer, next_writer))
{
array[past_writer] = std::move_if_noexcept(object);
return true;
}
}
return false;
}
bool try_pop(Type & object) const
{
auto past_reader = reader.load();
auto next_reader = increment(past_reader);
if (past_reader != writer.load())
{
if (reader.compare_exchange_weak(past_reader, next_reader))
{
object = std::move_if_noexcept(array[past_reader]);
return true;
}
}
return false;
}
bool empty() const
{
return reader.load() == writer.load();
}
private:
std::size_t increment(std::size_t index) const
{
return (index + 1) % Capacity;
}
mutable std::atomic_size_t reader { 0 };
mutable std::atomic_size_t writer { 0 };
mutable std::array<Type, Capacity> array;
};
Is there anything I could have missed
Well yes probably. The real thing you need to watch with lock free programming is throughput. Just because it is lock free does not mean it is faster. Have you written a locking version to test throughput characteristics against? \$\endgroup\$ – Martin York Oct 12 '15 at 1:58