/* * Copyright (C) 2008-2019 TrinityCore * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef MPSCQueue_h__ #define MPSCQueue_h__ #include #include // C++ implementation of Dmitry Vyukov's lock free MPSC queue // http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue template class MPSCQueue { public: MPSCQueue() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed)) { Node* front = _head.load(std::memory_order_relaxed); front->Next.store(nullptr, std::memory_order_relaxed); } ~MPSCQueue() { T* output; while (this->Dequeue(output)) ; Node* front = _head.load(std::memory_order_relaxed); delete front; } void Enqueue(T* input) { Node* node = new Node(input); Node* prevHead = _head.exchange(node, std::memory_order_acq_rel); prevHead->Next.store(node, std::memory_order_release); } bool Dequeue(T*& result) { Node* tail = _tail.load(std::memory_order_relaxed); Node* next = tail->Next.load(std::memory_order_acquire); if (!next) return false; result = next->Data; _tail.store(next, std::memory_order_release); delete tail; return true; } private: struct Node { Node() = default; explicit Node(T* data) : Data(data) { Next.store(nullptr, std::memory_order_relaxed); } T* Data; std::atomic Next; }; std::atomic _head; std::atomic _tail; MPSCQueue(MPSCQueue const&) = delete; MPSCQueue& operator=(MPSCQueue const&) = delete; }; #endif // MPSCQueue_h__