   A Task based aproach. What you think. [Source Code]
/*=====================================================================================================================================================================================================*//**    \file ctask.h    \author Damian Gabriel PazDescription*//*======================================================================================================================================================================================================*/#ifndef INCLUDE_NAMESPACE_NAME_ctask_H#define INCLUDE_NAMESPACE_NAME_ctask_H/*-= Includes =- =========================================================================================================================================================================================*///#include ""#include <iostream>#include <string>//using namespace namespace;/*========================================================================================================================================================================================================*/namespace owl{namespace task{    /*-= ctask =- ================================================================================================================================================================================*//**Description    *//* =================================================================================================================================================================================================*/class ctask{protected:std::stringtask_name;booltask_paused;booltask_running;ctask*task_root;ctask*task_parent;ctask*task_previous;ctask*task_next;ctask*task_child;public:ctask ( void ):task_root(NULL), task_parent(NULL), task_previous(NULL), task_next(NULL), task_child(NULL), task_name("untitled"), task_paused(false), task_running(true){}virtual ~ctask( void ) {std::cout<<"task ended"<<std::endl;}virtual boolinitialize() {return true;}virtual voidterminate() {}virtual voidupdate() {}bool run(){if (task_running){if (task_paused) return true;update();if (NULL!=task_child) task_child->run();if (NULL!=task_next) task_next->run();return true;}end_task();return false;}void add_task (ctask* ptask){if (NULL!=task_child)task_child->add_next_task(ptask);else{task_child = ptask;task_child->task_parent = this;if (NULL!=task_root)task_child->task_root = task_root;elsetask_child->task_root = this;task_child->initialize();}}std::string call_stack(){std::string stack;if (NULL!=task_parent)stack+=task_parent->call_stack()+"->";stack+=task_name;return stack;}void exit_task() {task_running=false;}private:void add_next_task (ctask* ptask){if (NULL!=task_next)task_next->add_next_task(ptask);else{task_next = ptask;task_next->task_previous = this;task_next->task_parent = task_parent;task_next->task_root = task_root;task_next->initialize();}}void end_task(){if (NULL!=task_child){task_child->end_task();delete task_child;task_child = NULL;}if (NULL!=task_next){task_next->end_task();delete task_next;task_next = NULL;}terminate();task_running = false;}};void run(ctask* task){task->initialize();while (task->run());delete task;}}//namespace task}//namespace owl/*========================================================================================================================================================================================================*/#endif/*=========================================================================================================================================================================================================*-= End of file =-==========================================================================================================================================================================================================*/#include <iostream>using namespace std;#include "ctask.h"using namespace owl::task;class second_child : public ctask{public:second_child() {task_name="second_child";}void update(){cout << call_stack()<<endl;task_root->exit_task();}};class first_child : public ctask{public:first_child() {task_name="first_child";}bool initialize(){return true;}void update(){cout << call_stack()<<endl;}};class root : public ctask{public:root() {task_name="ctask_root";}bool initialize(){add_task (new first_child);add_task (new second_child);return true;}void update(){cout << call_stack()<<endl;}};int main(){    owl::task::run(new root());    return 0;}Output:ctask_rootctask_root->first_childctask_root->second_childtask endedtask endedtask ended
  Forgive me the question, but a task-based approach to what? I've looked at the code you posted but I can't quite envision a practical use for this. Please describe which problem you think this solves.   ;Quote:Original post by Red AntForgive me the question, but a task-based approach to what? I've looked at the code you posted but I can't quite envision a practical use for this. Please describe which problem you think this solves.heh, a task based aproach for structuring a program execution, like proposed in superpig's article "Enginuity". I was bored and I tryied to write a simpler version of what he did there. I find it interesting the posibility of running different parts of a program as tasks that can be added/removed/paused as needed, but I still can't figure out how to make it easy to implement/mantain.   ;  The way I understand your code is that the ctask class sort of represents a job queue. A worker thread then runs all of the jobs, one by one, until they're all done. Other threads can request that a particular job is suspended or even outright canceled. Is that correct?If so, I think if you actually try to use your code in an actual multi-threaded program, you'll find that you'll quickly run into problems due to the lack of any synchronization in your code. If I have misinterpreted anything, please correct me.P.S. Do you have a link to the article you mentioned?   ;Quote:Original post by Red AntThe way I understand your code is that the ctask class sort of represents a job queue. A worker thread then runs all of the jobs, one by one, until they're all done. Other threads can request that a particular job is suspended or even outright canceled. Is that correct?If so, I think if you actually try to use your code in an actual multi-threaded program, you'll find that you'll quickly run into problems due to the lack of any synchronization in your code. If I have misinterpreted anything, please correct me.P.S. Do you have a link to the article you mentioned?Yes, that'd be another use. The code I posted isn't complete. I like this aproach because it offers the posibility of adapting a custom profiler (per task) or to write features that can be inserted/removed as many times as you want at runtime.All the times I've tried to implement this, I ended up with lots of nasty macros and the comunication with different objects that are not task becomes ugly.Enginuity, Part III;  Can't help you with making it thread safe (but nothing wrong with running it all in a single thread, if you can make tasks short or re-entrant), but I would definitely separate out the code managing the task execution from the actual task itself, SRP and all that. Some other ideas for where you could take this (partially based on Millington's Artificial Intelligence for Games, which I happen to be reading right now): Task execution frequency and offset for automatically spreading out tasks equally among ticks. Accounting for time and passing the time slice left over for execution (could be scaled based on task priorities) to the task and making tasks re-entrant would help you execute processing-intensive tasks over multiple ticks. For these same reasons I would get rid of the next/child thing and make that an implicit part of the TaskScheduler (which can be a Task itself if you want to chain them, so that a TaskScheduler can schedule other TaskSchedulers to run, but I'd separate the code among those two classes).I think there can be some uses for this apart from AI, basically for any kind of intensive task that you want to spread out over some frames - recalculating terrain meshes maybe? Using it for the entire program should be possible but somehow feels a bit over-engineered to me.   