Newer
Older
Import / projects / Gameloft / core / Utils / ASyncTask.h
#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;
  };

}