From 0c54d5e37b8d0affa4bd4ecbc43233f33878e843 Mon Sep 17 00:00:00 2001 From: Anselme Date: Wed, 1 Feb 2017 17:44:54 +0100 Subject: [PATCH] first iteration of the Provider and Task classes --- CMakeLists.txt | 2 +- src/provider.cpp | 2 + src/provider.h | 41 ++++++++++++++ src/taskmanager.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++ src/taskmanager.h | 66 +++++++++++++++++++++++ 5 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 src/provider.cpp create mode 100644 src/provider.h create mode 100644 src/taskmanager.cpp create mode 100644 src/taskmanager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ba87d02..2e5638b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(VERSION_MAJOR 0) set(VERSION_MINOR 1) # choose source file -file(GLOB LIB_SRC_LIST src/property.cpp src/serializable.cpp src/serializationmanager.cpp) +file(GLOB LIB_SRC_LIST src/property.cpp src/serializable.cpp src/serializationmanager.cpp src/taskmanager.cpp src/provider.cpp) file(GLOB LIB_HEAD_LIST src/*.h) set(EXEC_SRC_LIST src/main.cpp) diff --git a/src/provider.cpp b/src/provider.cpp new file mode 100644 index 0000000..fbfa767 --- /dev/null +++ b/src/provider.cpp @@ -0,0 +1,2 @@ +#include "provider.h" + diff --git a/src/provider.h b/src/provider.h new file mode 100644 index 0000000..b3bade4 --- /dev/null +++ b/src/provider.h @@ -0,0 +1,41 @@ +#ifndef PROVIDER_H +#define PROVIDER_H + +#include "serializable.h" + +#include "taskmanager.h" + +class AbstractProvider : public Serializable +{ +public: + virtual Task* getTask() = 0; +}; + +template +class Provider : public AbstractProvider +{ +protected: + struct ProviderTask : public Task + { + T* m_object = nullptr; + int m_progress = 0; + int m_flags; + std::string m_providerName; + + /** + * @brief This should be overloaded + */ + virtual void performTask() { m_object = new T(); m_progress = 1; } + + virtual int getProgressInt() { } + virtual Task::TaskTypeFlags getFlags() { return m_flags; } + virtual const std::string &getLabel() { return m_providerName; } + }; + + ProviderTask m_task; +public: + virtual Task* getTask() { return (Task*)&m_task; } + virtual T* provide() { return m_task.m_object; } +}; + +#endif // PROVIDER_H diff --git a/src/taskmanager.cpp b/src/taskmanager.cpp new file mode 100644 index 0000000..a9dfb7e --- /dev/null +++ b/src/taskmanager.cpp @@ -0,0 +1,129 @@ +#include "taskmanager.h" + +// TASK THREAD +TaskThread::~TaskThread() +{ + waitUntilOver(); + for(std::thread * t : m_threads) + delete t; +} + +void TaskThread::addTask(Task* task) +{ + m_tasks.push_back(task); + ++m_totalTasks; +} + +void TaskThread::start(int nbThreads) +{ + for(int i=0; iperformTask(); + m_mutex.lock(); + + delete m_currentTasks[id]; + m_currentTasks[id] = nullptr; + ++m_tasksPerformed; + } + m_mutex.unlock(); +} + +void TaskThread::waitUntilOver() +{ + for(std::thread * t : m_threads) + t->join(); +} + +bool TaskThread::isOver() +{ + return m_tasksPerformed == m_totalTasks; +} + +float TaskThread::getProgressProportion() +{ + float progress = 1.f; + m_mutex.lock(); + if(!isOver()) + { + progress = m_tasksPerformed; + for(Task* t : m_currentTasks) + { + if(t != nullptr) + progress += t->getProgressProportion(); + } + progress /= m_totalTasks; + } + m_mutex.unlock(); + return progress; +} + +// TASK MANAGER +void TaskManager::addTask(Task* task) +{ + int flags = task->getFlags(); + if(flags & Task::GPU) + m_gpuTasks.addTask(task); + else if(flags & Task::HDD) + m_hddTasks.addTask(task); + else if(flags & Task::NET) + m_netTasks.addTask(task); + else + m_cpuTasks.addTask(task); +} + +void TaskManager::start() +{ + m_hddTasks.start(1); // Reading multiple files simultaneously makes no sense + m_cpuTasks.start(4); + m_gpuTasks.start(1); // GPU tasks must be regouped on only one thread to easily have access to an OpenGL context + m_netTasks.start(4); +} + +void TaskManager::waitUntilOver() +{ + m_hddTasks.waitUntilOver(); + m_cpuTasks.waitUntilOver(); + m_gpuTasks.waitUntilOver(); + m_netTasks.waitUntilOver(); +} + +bool TaskManager::isOver() +{ + return m_hddTasks.isOver() + && m_cpuTasks.isOver() + && m_gpuTasks.isOver() + && m_netTasks.isOver(); +} + +float TaskManager::getProgress(int flags) +{ + float progress = 0; + int nbTypes = 0; + if(flags & Task::GPU) + progress += m_gpuTasks.getProgressProportion(), ++nbTypes; + else if(flags & Task::HDD) + progress += m_hddTasks.getProgressProportion(), ++nbTypes; + else if(flags & Task::NET) + progress += m_netTasks.getProgressProportion(), ++nbTypes; + else + progress += m_cpuTasks.getProgressProportion(), ++nbTypes; + if(nbTypes != 0) + return progress/nbTypes; + else + return 1.f; +} diff --git a/src/taskmanager.h b/src/taskmanager.h new file mode 100644 index 0000000..0b95894 --- /dev/null +++ b/src/taskmanager.h @@ -0,0 +1,66 @@ +#ifndef TASKMANAGER_H +#define TASKMANAGER_H + +#include +#include +#include +#include +#include + +class Task +{ +public: + enum TaskTypeFlags + { + HDD, // saving of loading to the file system + CPU, // computing something + GPU, // computing something on the GPU or transferring data between the RAM and the GPU RAM + NET // sending or receiving from the network + }; + + virtual void performTask() = 0; + + virtual int getProgressInt() = 0; + virtual int getProgressTotal() { return 1; } + virtual float getProgressProportion() { return float(getProgressInt())/float(getProgressTotal()); } + + virtual TaskTypeFlags getFlags() = 0; + virtual const std::string &getLabel() = 0; +}; + +class TaskThread +{ + std::list m_tasks; + std::vector m_threads; + std::vector m_currentTasks; + std::mutex m_mutex; + int m_tasksPerformed; + int m_totalTasks; + + void run(int id); +public: + ~TaskThread(); + + void addTask(Task* task); + void start(int nbThreads = 1); + void waitUntilOver(); + bool isOver(); + float getProgressProportion(); +}; + +class TaskManager +{ + TaskThread m_hddTasks; + TaskThread m_cpuTasks; + TaskThread m_gpuTasks; + TaskThread m_netTasks; + +public: + void addTask(Task* task); + void start(); + void waitUntilOver(); + bool isOver(); + float getProgress(int flags = Task::CPU | Task::GPU | Task::HDD | Task::NET); +}; + +#endif // TASKMANAGER_H