Bosma / Scheduler

Modern C++ Scheduling Library
MIT License
272 stars 74 forks source link

Disable/remove task #4

Open asmyasnikov opened 6 years ago

asmyasnikov commented 6 years ago

Hello! Tell me how to disable/remove task, created by interval/every method? This need to me for stopping execution task without restart sheduller... For example I may throw spatial exception from body of task, which cancelled schedulling this task in a future...

klukaspl commented 6 years ago

Hi,

I will be also interested in how to disable or remove particular task that is already set. How can I refer to each particular task in the scheduler?

BR,

Krzysztof

Bosma commented 6 years ago

Yes I agree this feature is required. I have some choices on how to implement it and would love any suggestions. I'll begin work on it some time soon.

klukaspl commented 6 years ago

Hi, Maybe it could based on unique id of each task or applied name? Then probably the time of execution, execution function and the name/uid is necessary to pass when adding to the pool. And to remove the task we could refer by its name to point it.

I am not sure if this is the simplest way - but maybe worth of consider.

In my application I need to define some schedules that could for example switchON the device and then switchOFF. For this I need for example use two separate tasks "at" type, or if it is recurring action two "cron" tasks. I was thinking to build some object as schedule for example "Schedule(ScheduleName, timeOn, timeOff)" and in the background launch two separate tasks .at(dateON, OnAction) and .at(dateOFF, OffAction). When they are run at once they will be deleted. But when I have recurrent schedule and I am trying to use .cron(dateON, OnAction) and .cron(dateOFF, OffAction) I have no reference to those created tasks and later on I could have problem when user will decide to delete those tasks.

asmyasnikov commented 6 years ago

Hi! Disabling task by id is not safely. Because any code block may be called method of disabling task by random id without guarantee of disabling specific task. I suggest throw exception from specific task who needed to disabling. And Scheduller was catch exception in manage_tasks() like this try{ task->f(); }catch(SchedullerDisableException e){ end_of_tasks_to_run.insert(task); } And task may be like this std::atomic<bool> flag; s.in(1min, []() { if(flag) std::cout << "in one minute" << std::endl; else throw SchedullerDisableException(); });

klukaspl commented 6 years ago

Hi,

Thanks, I agree that this could be a way. I am currently trying to test what you suggest. One question, I suppose that end_of_tasks_to_run is some kind of container? How to delete the task from the task to do list? EDIT: end_of_tasks_to_run does not have insert member function. EDIT: calling the exception on my side is just causing that the action is not executed on schedule period - it could be way of enabling/disabling task. When catching the exception I am trying to call some my function delete_task to remove the task totally from execution queue (from tasks). It looks like that: void delete_task(std::shared_ptr &t) { std::cout << "Here place delete action" << std::endl;

     for(auto it = tasks.begin(); it != tasks.end(); it++){
         if(it->second == t){
             std::cout << "The element found for time " << '\n';
             tasks.erase(it->first, it->second);
         }
     }
  }

but it seems it is never executed. My manage_task looks as follow:

` void manage_tasks() { std::lock_guard l(lock); auto end_of_tasks_to_run = tasks.upper_bound(Clock::now()); std::shared_ptr &task = (*(tasks.begin())).second;

 try {

      // if there are any tasks to be run and removed
      if (end_of_tasks_to_run != tasks.begin()) {
        // keep track of tasks that will be re-added
        decltype(tasks) recurred_tasks;

        // for all tasks that have been triggered
        for (auto i = tasks.begin(); i != end_of_tasks_to_run; ++i) {
          task = (*i).second;

          if (task->interval) {
            // if it's an interval task, only add the task back after f() is completed
            threads.push([this, task](int) {
                task->f();
                // no risk of race-condition,
                // add_task() will wait for manage_tasks() to release lock
                add_task(task->get_new_time(), task);
            });
          } else {
            threads.push([task](int) {
                task->f();
            });
            // calculate time of next run and add the new task to the tasks to be recurred
            if (task->recur)
              recurred_tasks.emplace(task->get_new_time(), std::move(task));
          }
        }

        // remove the completed tasks
        tasks.erase(tasks.begin(), end_of_tasks_to_run);

        // re-add the tasks that are recurring
        for (auto &task : recurred_tasks)
          tasks.emplace(task.first, std::move(task.second));
      }
    }
    catch(SchedulerDisableException e)
    {
         std::cout << "here call the method to remove the particular task" << std::endl;
         delete_task(task);
    }

} ` Do you have any idea how to force it to work?

BR,

Krzysztof.