diff --git a/libs/TaskQueue.h b/libs/TaskQueue.h new file mode 100644 index 0000000000..5be601cc1c --- /dev/null +++ b/libs/TaskQueue.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include + +namespace util +{ + +class TaskQueue +{ +private: + std::mutex _lock; + + std::list> _queue; + + std::future _current; + +public: + ~TaskQueue() + { + clear(); + } + + // Adds the given task to the queue. This will launch the task + // immediately if no other task is currently processed + void enqueue(const std::function& task) + { + { + std::lock_guard lock(_lock); + _queue.push_front(task); + } + + if (isIdle()) + { + startNextTask(); + } + } + + // Clears the queue. This might block waiting for any currently + // active taks to finish + void clear() + { + { + // Lock the queue and remove any tasks such that no new ones are added + std::lock_guard lock(_lock); + _queue.clear(); + } + + // Clear (and possibly) wait for the currently active future object + _current = std::future(); + } + +private: + bool isIdle() const + { + return !_current.valid() || + _current.wait_for(std::chrono::seconds(0)) == std::future_status::ready; + } + + void startNextTask() + { + std::lock_guard lock(_lock); + + if (_queue.empty()) + { + return; + } + + // No active task, dispatch a new one + auto frontOfQueue = _queue.front(); + _queue.pop_front(); + + // Wrap the given task in our own lambda to start the next task right afterwards + _current = std::async(std::launch::async, [this, frontOfQueue]() + { + frontOfQueue(); + startNextTask(); + }); + } +}; + +} diff --git a/tools/msvc/libs.vcxproj b/tools/msvc/libs.vcxproj index a6ad7e7233..1cd57219ab 100644 --- a/tools/msvc/libs.vcxproj +++ b/tools/msvc/libs.vcxproj @@ -235,6 +235,7 @@ + diff --git a/tools/msvc/libs.vcxproj.filters b/tools/msvc/libs.vcxproj.filters index 853346b12a..56aa961830 100644 --- a/tools/msvc/libs.vcxproj.filters +++ b/tools/msvc/libs.vcxproj.filters @@ -261,6 +261,7 @@ selection +