Shared/Util: Introduce a task scheduler which schedules task with c++11 techniques.

* Use std::function as callback (methods, lamdas & std::bind).
* Uses std::chrono::duration as duration type (Milliseconds, Seconds...)
  - With c++11 user defined literals we could just write "11s" for example (MSVS 2015, gcc & clang).
* Provides a lot of overloads for easier usage:
  - Static durations or random durations between min and max.
  - Named (with group ids - group id 0 is possible) or anonymous tasks.
  - Asynchronous tasks.
* Is adapted to the current needs of scripting:
  - Repeat tasks through the TaskContext
  - Schedule new tasks from the context.
  - Provides access to the times repeat counter of a task,
    this will help to schedule multi step events (dialogs for example).

See https://gist.github.com/Naios/6d143538abdc3d32fd2b for usage examples.
This commit is contained in:
Naios committed 2015-05-31 19:32:09 +02:00
1 parent e500cda6a9
commit da77a90aa9
3 files changed
+796

No files matched your search

@@ -6,3 +6,4 @@
#include "SQLOperation.h"
#include "Errors.h"
#include "TypeList.h"
#include "TaskScheduler.h"
@@ -0,0 +1,204 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TaskScheduler.h"
TaskScheduler& TaskScheduler::Update()
{
_now = clock_t::now();
Dispatch();
return *this;
}
TaskScheduler& TaskScheduler::Update(size_t const milliseconds)
{
return Update(std::chrono::milliseconds(milliseconds));
}
TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable)
{
_asyncHolder.push(callable);
return *this;
}
TaskScheduler& TaskScheduler::CancelAll()
{
/// Clear the task holder
_task_holder.Clear();
_asyncHolder = AsyncHolder();
return *this;
}
TaskScheduler& TaskScheduler::CancelGroup(group_t const group)
{
_task_holder.RemoveIf([group](TaskContainer const& task) -> bool
{
return task->IsInGroup(group);
});
return *this;
}
TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups)
{
std::for_each(groups.begin(), groups.end(),
std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1));
return *this;
}
TaskScheduler& TaskScheduler::InsertTask(TaskContainer task)
{
_task_holder.Push(std::forward<TaskContainer>(task));
return *this;
}
void TaskScheduler::Dispatch()
{
// Process all asyncs
while (!_asyncHolder.empty())
{
_asyncHolder.front()();
_asyncHolder.pop();
}
while (!_task_holder.IsEmpty())
{
if (_task_holder.First()->_end > _now)
break;
// Perfect forward the context to the handler
// Use weak references to catch destruction before callbacks.
TaskContext context(new TaskContextInstance(_task_holder.Pop(),
std::weak_ptr<TaskScheduler>(self_reference)));
// Invoke the context
context->Invoke();
}
}
void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
{
container.insert(task);
}
auto TaskScheduler::TaskQueue::Pop() -> TaskContainer
{
TaskContainer result = *container.begin();
container.erase(container.begin());
return result;
}
auto TaskScheduler::TaskQueue::First() const -> TaskContainer const&
{
return *container.begin();
}
void TaskScheduler::TaskQueue::Clear()
{
container.clear();
}
void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter)
{
for (auto itr = container.begin(); itr != container.end();)
if (filter(*itr))
itr = container.erase(itr);
else
++itr;
}
void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter)
{
std::vector<TaskContainer> cache;
for (auto itr = container.begin(); itr != container.end();)
if (filter(*itr))
{
cache.push_back(*itr);
itr = container.erase(itr);
}
else
++itr;
container.insert(cache.begin(), cache.end());
}
bool TaskScheduler::TaskQueue::IsEmpty() const
{
return container.empty();
}
TaskContextInstance& TaskContextInstance::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply)
{
if (auto const owner = _owner.lock())
apply(*owner);
return *this;
}
bool TaskContextInstance::IsInGroup(TaskScheduler::group_t const group) const
{
return _task->IsInGroup(group);
}
TaskContextInstance& TaskContextInstance::SetGroup(TaskScheduler::group_t const group)
{
_task->_group = group;
return *this;
}
TaskContextInstance& TaskContextInstance::ClearGroup()
{
_task->_group = boost::none;
return *this;
}
TaskScheduler::repeated_t TaskContextInstance::GetRepeatCounter() const
{
return _task->_repeated;
}
TaskContextInstance& TaskContextInstance::Async(std::function<void()> const& callable)
{
return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable));
}
TaskContextInstance& TaskContextInstance::CancelAll()
{
return Dispatch(std::mem_fn(&TaskScheduler::CancelAll));
}
TaskContextInstance& TaskContextInstance::CancelGroup(TaskScheduler::group_t const group)
{
return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group));
}
TaskContextInstance& TaskContextInstance::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups)
{
return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, groups));
}
void TaskContextInstance::AssertOnConsumed()
{
// This was adapted to TC to prevent static analysis tools from complaining.
// If you encounter this assertion check if you repeat a TaskContext more then 1 time!
ASSERT(_task && "Bad task logic, task context was consumed already!");
}
void TaskContextInstance::Invoke()
{
_task->_task(shared_from_this());
}
+591
View File
@@ -0,0 +1,591 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TASK_SCHEDULER_H_
#define _TASK_SCHEDULER_H_
#include <algorithm>
#include <chrono>
#include <vector>
#include <queue>
#include <memory>
#include <utility>
#include <set>
#include <boost/optional.hpp>
#include "Util.h"
class TaskContextInstance;
typedef std::shared_ptr<TaskContextInstance> TaskContext;
/// The TaskScheduler class provides the ability to schedule std::function's in the near future.
/// Use TaskScheduler::Update to update the scheduler.
/// Popular methods are:
/// * Schedule (Schedules a std::function which will be executed in the near future).
/// * Schedules an asynchronous function which will be executed at the next update tick.
/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks).
/// Tasks are organized in groups (uint), multiple tasks can have the same group id,
/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id!
/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides
/// access to the function schedule plan which makes it possible to repeat the task
/// with the same duration or a new one.
/// It also provides access to the repeat counter which is useful for task that repeat itself often
/// but behave different every time (spoken event dialogs for example).
class TaskScheduler
{
friend class TaskContextInstance;
// Time definitions (use steady clock)
typedef std::chrono::steady_clock clock_t;
typedef clock_t::time_point timepoint_t;
typedef clock_t::duration duration_t;
// Task group type
typedef uint32 group_t;
// Task repeated type
typedef uint32 repeated_t;
// Task handle type
typedef std::function<void(TaskContext)> task_handler_t;
class Task
{
friend class TaskContextInstance;
friend class TaskScheduler;
timepoint_t _end;
duration_t _duration;
boost::optional<group_t> _group;
repeated_t _repeated;
task_handler_t _task;
public:
// All Argument construct
Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group,
repeated_t const repeated, task_handler_t const& task)
: _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { }
// Minimal Argument construct
Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task)
: _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { }
// Copy construct
Task(Task const&) = delete;
// Move construct
Task(Task&&) = delete;
// Copy Assign
Task& operator= (Task const&) = default;
// Move Assign
Task& operator= (Task&& right) = delete;
// Order tasks by its end
inline bool operator< (Task const& other) const
{
return _end < other._end;
}
inline bool operator> (Task const& other) const
{
return _end > other._end;
}
// Compare tasks with its end
inline bool operator== (Task const& other)
{
return _end == other._end;
}
// Returns true if the task is in the given group
inline bool IsInGroup(group_t const group) const
{
return _group == group;
}
};
typedef std::shared_ptr<Task> TaskContainer;
/// Container which provides Task order, insert and reschedule operations.
struct Compare
{
bool operator() (TaskContainer const& left, TaskContainer const& right)
{
return (*left.get()) < (*right.get());
};
};
class TaskQueue
{
std::multiset<TaskContainer, Compare> container;
public:
// Pushes the task in the container
void Push(TaskContainer&& task);
/// Pops the task out of the container
TaskContainer Pop();
TaskContainer const& First() const;
void Clear();
void RemoveIf(std::function<bool(TaskContainer const&)> const& filter);
void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
bool IsEmpty() const;
};
/// Contains a self reference to track if this object was deleted or not.
std::shared_ptr<TaskScheduler> self_reference;
/// The current time point (now)
timepoint_t _now;
/// The Task Queue which contains all task objects.
TaskQueue _task_holder;
typedef std::queue<std::function<void()>> AsyncHolder;
/// Contains all asynchronous tasks which will be invoked at
/// the next update tick.
AsyncHolder _asyncHolder;
public:
TaskScheduler() : self_reference(this, [](TaskScheduler const*) { }),
_now(clock_t::now()) { }
TaskScheduler(TaskScheduler const&) = delete;
TaskScheduler(TaskScheduler&&) = delete;
TaskScheduler& operator= (TaskScheduler const&) = delete;
TaskScheduler& operator= (TaskScheduler&&) = delete;
/// Update the scheduler to the current time.
TaskScheduler& Update();
/// Update the scheduler with a difftime in ms.
TaskScheduler& Update(size_t const milliseconds);
/// Update the scheduler with a difftime.
template<class _Rep, class _Period>
TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime)
{
_now += difftime;
Dispatch();
return *this;
}
/// Schedule an callable function that is executed at the next update tick.
/// Its safe to modify the TaskScheduler from within the callable.
TaskScheduler& Async(std::function<void()> const& callable);
/// Schedule an event with a fixed rate.
/// Never call this from within a task context! Use TaskContext::Schedule instead!
template<class _Rep, class _Period>
TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
task_handler_t const& task)
{
return ScheduleAt(_now, time, task);
}
/// Schedule an event with a fixed rate.
/// Never call this from within a task context! Use TaskContext::Schedule instead!
template<class _Rep, class _Period>
TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time,
group_t const group, task_handler_t const& task)
{
return ScheduleAt(_now, time, group, task);
}
/// Schedule an event with a randomized rate between min and max rate.
/// Never call this from within a task context! Use TaskContext::Schedule instead!
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task)
{
return Schedule(RandomDurationBetween(min, max), task);
}
/// Schedule an event with a fixed rate.
/// Never call this from within a task context! Use TaskContext::Schedule instead!
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group,
task_handler_t const& task)
{
return Schedule(RandomDurationBetween(min, max), group, task);
}
/// Cancels all tasks.
/// Never call this from within a task context! Use TaskContext::CancelAll instead!
TaskScheduler& CancelAll();
/// Cancel all tasks of a single group.
/// Never call this from within a task context! Use TaskContext::CancelGroup instead!
TaskScheduler& CancelGroup(group_t const group);
/// Cancels all groups in the given std::vector.
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
/// Delays all tasks with the given duration.
template<class _Rep, class _Period>
TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
{
_task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool
{
task->_end += duration;
return true;
});
return *this;
}
/// Delays all tasks with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return DelayAll(RandomDurationBetween(min, max));
}
/// Delays all tasks of a group with the given duration.
template<class _Rep, class _Period>
TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
{
_task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool
{
if (task->IsInGroup(group))
{
task->_end += duration;
return true;
}
else
return false;
});
return *this;
}
/// Delays all tasks of a group with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& DelayGroup(group_t const group,
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return DelayGroup(group, RandomDurationBetween(min, max));
}
/// Reschedule all tasks with a given duration.
template<class _Rep, class _Period>
TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
{
auto const end = _now + duration;
_task_holder.ModifyIf([end](TaskContainer const& task) -> bool
{
task->_end = end;
return true;
});
return *this;
}
/// Reschedule all tasks with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return RescheduleAll(RandomDurationBetween(min, max));
}
/// Reschedule all tasks of a group with the given duration.
template<class _Rep, class _Period>
TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
{
auto const end = _now + duration;
_task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool
{
if (task->IsInGroup(group))
{
task->_end = end;
return true;
}
else
return false;
});
return *this;
}
/// Reschedule all tasks of a group with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskScheduler& RescheduleGroup(group_t const group,
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return RescheduleGroup(group, RandomDurationBetween(min, max));
}
private:
/// Insert a new task to the enqueued tasks.
TaskScheduler& InsertTask(TaskContainer task);
template<class _Rep, class _Period>
TaskScheduler& ScheduleAt(timepoint_t const& end,
std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task)
{
return InsertTask(TaskContainer(new Task(end + time, time, task)));
}
/// Schedule an event with a fixed rate.
/// Never call this from within a task context! Use TaskContext::schedule instead!
template<class _Rep, class _Period>
TaskScheduler& ScheduleAt(timepoint_t const& end,
std::chrono::duration<_Rep, _Period> const& time,
group_t const group, task_handler_t const& task)
{
static repeated_t const DEFAULT_REPEATED = 0;
return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task)));
}
// Returns a random duration between min and max
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
std::chrono::milliseconds
static RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min);
auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max);
// TC specific: use SFMT URandom
return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count()));
}
/// Dispatch remaining tasks
void Dispatch();
};
class TaskContextInstance
: public std::enable_shared_from_this<TaskContextInstance>
{
friend class TaskScheduler;
/// Associated task
TaskScheduler::TaskContainer _task;
/// Owner
std::weak_ptr<TaskScheduler> const _owner;
/// Dispatches an action safe on the TaskScheduler
TaskContextInstance& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply);
public:
explicit TaskContextInstance(TaskScheduler::TaskContainer task, std::weak_ptr<TaskScheduler>&& owner)
: _task(task), _owner(owner) { }
/// Returns true if the event is in the given group
bool IsInGroup(TaskScheduler::group_t const group) const;
/// Sets the event in the given group
TaskContextInstance& SetGroup(TaskScheduler::group_t const group);
/// Removes the group from the event
TaskContextInstance& ClearGroup();
/// Returns the repeat counter which increases every time the task is repeated.
TaskScheduler::repeated_t GetRepeatCounter() const;
/// Repeats the event and sets a new duration.
/// std::chrono::seconds(5) for example.
/// This will consume the task context, its not possible to repeat the task again
/// from the same task context!
template<class _Rep, class _Period>
TaskContextInstance& Repeat(std::chrono::duration<_Rep, _Period> const& duration)
{
AssertOnConsumed();
// Set new duration, in-context timing and increment repeat counter
_task->_duration = duration;
_task->_end += duration;
_task->_repeated += 1;
return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task));
}
/// Repeats the event with the same duration.
/// This will consume the task context, its not possible to repeat the task again
/// from the same task context!
TaskContextInstance& Repeat()
{
return Repeat(_task->_duration);
}
/// Repeats the event and set a new duration that is randomized between min and max.
/// std::chrono::seconds(5) for example.
/// This will consume the task context, its not possible to repeat the task again
/// from the same task context!
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return Repeat(TaskScheduler::RandomDurationBetween(min, max));
}
/// Schedule a callable function that is executed at the next update tick from within the context.
/// Its safe to modify the TaskScheduler from within the callable.
TaskContextInstance& Async(std::function<void()> const& callable);
/// Schedule an event with a fixed rate from within the context.
/// Its possible that the new event is executed immediately!
/// Use TaskScheduler::Async to create a task
/// which will be called at the next update tick.
template<class _Rep, class _Period>
TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time,
TaskScheduler::task_handler_t const& task)
{
auto const end = _task->_end;
return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler&
{
return scheduler.ScheduleAt<_Rep, _Period>(end, time, task);
});
}
/// Schedule an event with a fixed rate from within the context.
/// Its possible that the new event is executed immediately!
/// Use TaskScheduler::Async to create a task
/// which will be called at the next update tick.
template<class _Rep, class _Period>
TaskContextInstance& Schedule(std::chrono::duration<_Rep, _Period> const& time,
TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task)
{
auto const end = _task->_end;
return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler&
{
return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task);
});
}
/// Schedule an event with a randomized rate between min and max rate from within the context.
/// Its possible that the new event is executed immediately!
/// Use TaskScheduler::Async to create a task
/// which will be called at the next update tick.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task)
{
return Schedule(TaskScheduler::RandomDurationBetween(min, max), task);
}
/// Schedule an event with a randomized rate between min and max rate from within the context.
/// Its possible that the new event is executed immediately!
/// Use TaskScheduler::Async to create a task
/// which will be called at the next update tick.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group,
TaskScheduler::task_handler_t const& task)
{
return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task);
}
/// Cancels all tasks from within the context.
TaskContextInstance& CancelAll();
/// Cancel all tasks of a single group from within the context.
TaskContextInstance& CancelGroup(TaskScheduler::group_t const group);
/// Cancels all groups in the given std::vector from within the context.
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
TaskContextInstance& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups);
/// Delays all tasks with the given duration from within the context.
template<class _Rep, class _Period>
TaskContextInstance& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)
{
return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration));
}
/// Delays all tasks with a random duration between min and max from within the context.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return DelayAll(TaskScheduler::RandomDurationBetween(min, max));
}
/// Delays all tasks of a group with the given duration from within the context.
template<class _Rep, class _Period>
TaskContextInstance& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
{
return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
}
/// Delays all tasks of a group with a random duration between min and max from within the context.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& DelayGroup(TaskScheduler::group_t const group,
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max));
}
/// Reschedule all tasks with the given duration.
template<class _Rep, class _Period>
TaskContextInstance& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration)
{
return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration));
}
/// Reschedule all tasks with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max));
}
/// Reschedule all tasks of a group with the given duration.
template<class _Rep, class _Period>
TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration)
{
return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration));
}
/// Reschedule all tasks of a group with a random duration between min and max.
template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight>
TaskContextInstance& RescheduleGroup(TaskScheduler::group_t const group,
std::chrono::duration<_RepLeft, _PeriodLeft> const& min,
std::chrono::duration<_RepRight, _PeriodRight> const& max)
{
return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max));
}
private:
void AssertOnConsumed();
/// Invokes the associated hook of the task.
void Invoke();
};
/// Milliseconds shorthand typedef.
typedef std::chrono::milliseconds Milliseconds;
/// Seconds shorthand typedef.
typedef std::chrono::seconds Seconds;
/// Minutes shorthand typedef.
typedef std::chrono::minutes Minutes;
/// Hours shorthand typedef.
typedef std::chrono::hours Hours;
#endif /// _TASK_SCHEDULER_H_