#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2023 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library 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 IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_SUPPORT_COLLECTIONS_CONCURRENTCOLLECTION_H #define NUCLEX_SUPPORT_COLLECTIONS_CONCURRENTCOLLECTION_H #include "Nuclex/Support/Config.h" #include // for std::size_t // Known implementations of lock-free collections for reference: // // Libraries of Lock-Free data structures: // https://github.com/mpoeter/xenium // https://liblfds.org/ (<-- Public Domain!) // https://github.com/khizmax/libcds // // Interesting design advice on Moody Camel's blog: // https://moodycamel.com/blog/2013/a-fast-lock-free-queue-for-c++.htm // https://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++.htm // // Intel's implementation (curiously not that good in benchmarks): // https://github.com/oneapi-src/oneTBB (Intel TBB under its new name) // https://github.com/oneapi-src/oneTBB/blob/master/include/oneapi/tbb/concurrent_queue.h // // Microsoft also ships a non-portable concurrent quue with Visual C++: // https://learn.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-queue-class // // "Battle Tested" implementation: // https://github.com/rigtorp/awesome-lockfree // https://github.com/rigtorp/MPMCQueue // // Moody Camel's implementation (I recommend this one): // https://github.com/cameron314/concurrentqueue // namespace Nuclex { namespace Support { namespace Collections { // ------------------------------------------------------------------------------------------- // /// How a concurrent collection is being accessed /// /// There fewer threads need to access the collection, the faster an implementation /// can be. This is used as a template parameter to decide implementation. /// enum class ConcurrentAccessBehavior { /// /// Only one thread is taking data and another, but only one, is producing it /// SingleProducerSingleConsumer, /// /// Only one thread is taking data, but multiple threads are adding data /// MultipleProducersSingleConsumer, /// /// Any number of threads is taking data and any number of threads is adding it /// MultipleProducersMultipleConsumers }; // ------------------------------------------------------------------------------------------- // /// Collection that can safely be used from multiple threads template< typename TElement, ConcurrentAccessBehavior accessBehavior = ( ConcurrentAccessBehavior::MultipleProducersMultipleConsumers ) > class ConcurrentCollection { /// Destroys the concurrent collection public: virtual ~ConcurrentCollection() = default; /// Tries to append an element to the collection in a thread-safe manner /// Element that will be appended to the collection /// True if the element was appended, false if there was no space left public: virtual bool TryAppend(const TElement &element) = 0; #if 0 // if the outcome is uncertain, move semantics mean the object is necessarily toast. /// /// Tries to move-append an element to the collection in a thread-safe manner /// /// Element that will be move-appended to the collection /// True if the element was appended, false if there was no space left public: virtual bool TryAppend(TElement &&element) = 0; #endif /// Tries to take an element from the collection /// Will receive the element taken from the collection /// /// True if an element was taken from the collection, false if the collection was empty /// public: virtual bool TryTake(TElement &element) = 0; /// Counts the numebr of elements current in the collection /// /// The approximate number of elements that had been in the collection during the call /// public: virtual std::size_t Count() const = 0; /// Checks if the collection is empty /// True if the collection had been empty during the call public: virtual bool IsEmpty() const = 0; }; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Support::Collections #endif // NUCLEX_SUPPORT_COLLECTIONS_CONCURRENTCOLLECTION_H