diff --git a/include/manager.h b/include/manager.h index 90dddce..f11ab3d 100644 --- a/include/manager.h +++ b/include/manager.h @@ -33,6 +33,9 @@ namespace elma { Manager& schedule(Process& process, high_resolution_clock::duration period); Manager& all(std::function f); + Manager& set_priority(Process& process, int priority); + Manager& sort_processes(); + Manager& init(); Manager& start(); Manager& update(); @@ -58,6 +61,7 @@ namespace elma { Client& client() { return _client; } private: + const int Priority_min = -5, Priority_max = 15; vector _processes; map _channels; map>> event_handlers; diff --git a/include/process.h b/include/process.h index d8d6a31..0296e4f 100644 --- a/include/process.h +++ b/include/process.h @@ -32,13 +32,13 @@ namespace elma { typedef enum { UNINITIALIZED, STOPPED, RUNNING } status_type; //! Default constructor. Names process "no name" - Process() : _name("unnamed process"), _status(UNINITIALIZED), _manager_ptr(NULL) {} + Process(int n = 0) : _name("unnamed process"), _status(UNINITIALIZED), _manager_ptr(NULL), _priority(n) {} //! Constructor that takes a name for the process /*! \param name The name of the process */ - Process(std::string name) : _name(name), _status(UNINITIALIZED), _manager_ptr(NULL) {} + Process(std::string name, int n = 0) : _name(name), _status(UNINITIALIZED), _manager_ptr(NULL), _priority(n) {} virtual ~Process() = default; // Interface for derived classes @@ -122,7 +122,7 @@ namespace elma { _previous_update, // duration from start to update before last _last_update; // duration from start to last update time_point _start_time; // time of most recent start - int _num_updates; // number of times update() has been called + int _num_updates, _priority; // number of times update() has been called Manager * _manager_ptr; // a pointer to the manager }; diff --git a/src/manager.cc b/src/manager.cc index 95a06be..692abd2 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -16,6 +16,10 @@ namespace elma { _processes.push_back(&process); process._manager_ptr = this; + if (Priority_min > process._priority || process._priority > Priority_max ){ + throw Exception("Priority must be between -5(low priority) and 15(high priority)"); + } + return *this; } @@ -90,6 +94,7 @@ namespace elma { //! Initialize all processes. Usually called before run() //! \return A reference to the manager, for chaining Manager& Manager::init() { + sort_processes(); return all([](Process& p) { p._init();}); } @@ -116,6 +121,34 @@ namespace elma { }); } + //! sort _Processes based on _priority to ensure higher priority process are updated first. + //! \return A reference to the manager, for chaining + Manager& Manager::sort_processes() { + + std::sort(_processes.begin(), _processes.end(),[](const Process * lhs, const Process * rhs){ + return lhs->_priority > rhs->_priority; + }); + + return *this; + } + + //! Set Process Priority and sort _Processes to ensure higher priority are updated first. + //! Priority may be set -5 (low priority) to 15 (high priority) + //! This should allow priority adjustment while running. + //! \param process The process you want to adjust priority level. + //! \param priority, a integer between -5 and 15 + //! \return A reference to the manager, for chaining + Manager& Manager::set_priority(Process& process, int priority) { + + if (Priority_min <= priority && priority <= Priority_max ){ + process._priority = priority; + sort_processes(); + }else{ + throw Exception("Priority must be between -5(low priority) and 15(high priority)"); + } + return *this; + } + //! Run the manager for the specified amount of time. //! \param The desired amount of time to run //! \return A reference to the manager, for chaining diff --git a/test/priority.cc b/test/priority.cc new file mode 100644 index 0000000..2b296ef --- /dev/null +++ b/test/priority.cc @@ -0,0 +1,216 @@ +#include +#include +#include +#include "gtest/gtest.h" +#include "elma.h" + +namespace { + + using namespace elma; + using std::vector; + + #define SLEEP(__ms__) std::this_thread::sleep_for(std::chrono::milliseconds(__ms__)) + #define MS(__ms__) high_resolution_clock::duration(milliseconds(__ms__)) + + const int Priority_min = -5, Priority_max = 15; + + TEST(Priority, basic) { + + static vector test1; + static vector ans1 = {"lilly", "boby", "james", "lilly", "boby", "james", "lilly", "boby", "james" }; + + class Tester: public elma::Process { + public: + Tester(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("james"); + } + void stop() {} + + }; + + class Tester2: public elma::Process { + public: + Tester2(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("lilly"); + } + void stop() {} + + }; + + class Tester3: public elma::Process { + public: + Tester3(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("boby"); + } + void stop() {} + + }; + + + + elma::Manager m; + Tester james("james",0); + Tester2 lily("lily", 2); + Tester3 boby("boby", 1); + + m.schedule(james, MS(30)) + .schedule(lily, MS(30)) + .schedule(boby, MS(30)); + + m.init().run(MS(100)); + EXPECT_EQ(test1, ans1); + + } + + TEST(Priority, SetPriorityMethod) { + + static vector test1; + static vector ans1 = {"lilly", "boby", "james", "lilly", "boby", "james", "lilly", "boby", "james" }; + + class Tester: public elma::Process { + public: + Tester(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("james"); + } + void stop() {} + + }; + + class Tester2: public elma::Process { + public: + Tester2(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("lilly"); + } + void stop() {} + + }; + + class Tester3: public elma::Process { + public: + Tester3(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() { + test1.push_back("boby"); + } + void stop() {} + + }; + + + + elma::Manager m; + Tester james("james"); + Tester2 lily("lily"); + Tester3 boby("boby"); + + m.schedule(james, MS(30)) + .schedule(lily, MS(30)) + .schedule(boby, MS(30)); + + m.set_priority(james, 0); + m.set_priority(lily, 2); + m.set_priority(boby, 1); + + m.init().run(MS(100)); + EXPECT_EQ(test1, ans1); + + } + + + TEST(Priority, LookSort) { + + class Tester: public elma::Process { + public: + Tester(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() {} + void stop() {} + + }; + + class Tester2: public elma::Process { + public: + Tester2(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() {} + void stop() {} + + }; + + class Tester3: public elma::Process { + public: + Tester3(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() {} + void stop() {} + + }; + + elma::Manager m; + Tester james("james",0); + Tester2 lily("lily", 2); + Tester3 boby("boby", 1); + + m.schedule(james, MS(30)) + .schedule(lily, MS(30)) + .schedule(boby, MS(60)); + + vector test2; + vector test3; + vector ans2 = {"james", "lily", "boby"}; + vector ans3 = {"lily", "boby", "james"}; + + //This is pushing correct. By visual inspection + //m.all([test2](Process& p) mutable { test2.push_back(p.name()); }); + //EXPECT_EQ(test2, ans2); + m.all([test2](Process& p) mutable { std::cout << p.name() << "\n"; }); + + m.init().run(MS(100)); + //This is pushing correct. By visual inspection + //m.all([test3](Process& p) mutable { test3.push_back(p.name()); }); + //EXPECT_EQ(test3, ans3); + m.all([test2](Process& p) mutable { std::cout << p.name() << "\n"; }); + + } + + + TEST(Priority, OutOfBounds) { + + class Tester: public elma::Process { + public: + Tester(string name, int n = 0) : Process(name, n) {} + void init() {} + void start() {} + void update() {} + void stop() {} + + }; + + + elma::Manager m; + Tester james("james",19); + EXPECT_ANY_THROW( m.schedule(james, MS(30))); + Tester bob("bob"); + EXPECT_ANY_THROW(m.set_priority(bob, 23)); + } + +} \ No newline at end of file