Advertisement
Guest User

Scheduler

a guest
Jul 7th, 2015
961
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.05 KB | None | 0 0
  1. --Scheduler.h----------------------------------------------------
  2. #pragma once
  3.  
  4. #include <map>
  5. #include <functional>
  6. #include <chrono>
  7. #include <mutex>
  8. #include <thread>
  9. #include <condition_variable>
  10. #include <memory>
  11.  
  12. //http://www.sgi.com/tech/stl/Multimap.html
  13.  
  14. typedef std::map<std::chrono::system_clock::time_point, std::function<void()>>::iterator task_it;
  15. //Single threaded scheduler
  16. class Scheduler {
  17. private:
  18.     std::multimap<std::chrono::system_clock::time_point, std::function<void()>> tasks;
  19.     std::mutex mutex;
  20.     std::unique_ptr<std::thread> thread;
  21.     std::condition_variable blocker;
  22.     bool go_on;
  23.  
  24. public:
  25.     //Scheduler& operator=(const Scheduler& rhs) = delete;
  26.     //Scheduler(const Scheduler& rhs) = delete;
  27.  
  28.     Scheduler();
  29.     ~Scheduler();
  30.  
  31.     void ThreadLoop();
  32.     task_it ScheduleAt(const std::chrono::system_clock::time_point & time, std::function<void()> func);
  33.     void ScheduleEvery(std::chrono::system_clock::duration interval, std::function<void()> func);
  34.     void unschedule(const task_it& handle);
  35. };
  36.  
  37. --Scheduler.cpp----------------------------------------------------
  38.  
  39. #include "Scheduler.h"
  40.  
  41.  
  42. Scheduler::Scheduler() : go_on(true) {
  43.     thread.reset(new std::thread([this](){ this->ThreadLoop(); }));
  44. }
  45.  
  46. Scheduler::~Scheduler() {
  47.     go_on = false;
  48.     ScheduleAt(std::chrono::system_clock::now(), [](){});
  49.     thread->join();
  50. }
  51.  
  52. void Scheduler::ThreadLoop() {
  53.     while(go_on) {
  54.         //Pop next scheduled task
  55.         std::function<void()> todo;
  56.         {
  57.            
  58.             std::unique_lock<std::mutex> lock(mutex);
  59.             auto now = std::chrono::system_clock::now();
  60.                        
  61.             if (tasks.empty()==false){
  62.                 printf("sheduler awoken. Now: %u. First task at: %u. condition %d\n", std::chrono::system_clock::to_time_t(now), std::chrono::system_clock::to_time_t(tasks.begin()->first), tasks.begin()->first <= now);
  63.             }
  64.             //added a 5 second hack because this keeps waking up 1 sec before it should
  65.             if ( tasks.empty()==false && tasks.begin()->first <= (now + std::chrono::seconds(5)))
  66.             {
  67.                 todo = tasks.begin()->second;
  68.                 tasks.erase(tasks.begin());
  69.             }
  70.         }
  71.        
  72.         // Run tasks while unlocked so tasks can schedule new tasks
  73.         if (todo){
  74.             printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!executing task!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
  75.             todo();
  76.         }
  77.  
  78.         //Block until next scheduled task
  79.         {
  80.             std::unique_lock<std::mutex> lock(mutex);
  81.             if (tasks.empty())
  82.                 blocker.wait(lock);
  83.             else
  84.                 blocker.wait_until(lock, tasks.begin()->first);
  85.         }
  86.     }
  87. }
  88.  
  89. task_it Scheduler::ScheduleAt(const std::chrono::system_clock::time_point & time, std::function<void()> func) {
  90.     std::unique_lock<std::mutex> lock(mutex);
  91.  
  92.     auto it = tasks.insert(std::make_pair(time, func));
  93.     if (it == tasks.begin())
  94.         blocker.notify_one();
  95.  
  96.     return it;  //Multimap has the important property that inserting a new element into a multimap does not invalidate iterators that point to existing elements. Erasing an element from a multimap also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.    
  97. }
  98.  
  99. void Scheduler::ScheduleEvery(std::chrono::system_clock::duration interval, std::function<void()> func){
  100.     std::function<void()> waitFunc = [this,interval,func](){
  101.         func();
  102.         this->ScheduleEvery(interval, func);
  103.     };
  104.     ScheduleAt(std::chrono::system_clock::now() + interval, waitFunc);
  105. }
  106.  
  107. void Scheduler::unschedule(const task_it& handle){
  108.     std::unique_lock<std::mutex> lock(mutex);
  109.     auto fresh_it = std::find(tasks.begin(), tasks.end(), *handle); //i get a fresh iterator to be on the safe side
  110.     if (fresh_it != tasks.end()){
  111.         tasks.erase(fresh_it);
  112.         blocker.notify_one(); //not sure this is nessessary but to be on the safe side
  113.     }
  114. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement