#pragma once
#pragma warning(disable : 4355)
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <atomic>
#include <string>
#include <condition_variable>
#include <functional>
#include "RKLog.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ASyncTask
{
enum LogLevel
{
LL_FATAL,
LL_ERROR,
LL_WARN,
LL_INFO,
LL_TRACE
};
class Task
{
public:
Task() {}
virtual ~Task() {}
// do some work that happens in a thread
virtual void Process() = 0;
// do something after this finishes, but in the update thread
virtual void Continuation() = 0;
// Return captured logging
typedef std::pair<LogLevel, std::string> LogEntry;
virtual const std::vector<LogEntry>& GetLogging() { return m_logging; }
private:
std::vector<LogEntry> m_logging;
// Helper function to add logging in the threaded task
template<typename ... Args>
void Log(LogLevel a_level, const char* a_fmt, Args ... a_args);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ASyncTaskManager
{
public:
explicit ASyncTaskManager(size_t a_threadCount);
~ASyncTaskManager();
void Shutdown();
void Update(std::chrono::milliseconds a_elapsedTime);
bool StartNewRequest(std::unique_ptr<Task> a_task);
// TODO? cancellations?
private:
int m_maxRequestsAtOnce = 10;
// need to keep track of threads so we can join them
std::vector<std::thread> m_workers;
// the task queue
std::queue<std::unique_ptr<Task>> m_tasks; // awaiting execution on a thread
std::queue<std::unique_ptr<Task>> m_finishedTasks; // awaiting continuation to be run
// synchronization
std::mutex m_queueMutex;
std::condition_variable m_condition;
bool m_shuttingDown = false;
};
}