You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.5 KiB
C
154 lines
5.5 KiB
C
|
1 month ago
|
/*------------------------------------------------------------------------------
|
||
|
|
* Copyright (c) 2023 by Bai Bing (seread@163.com)
|
||
|
|
* S++ COPYING file for copying and redistribution conditions.
|
||
|
|
*
|
||
|
|
* Alians IT Studio.
|
||
|
|
*----------------------------------------------------------------------------*/
|
||
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <atomic>
|
||
|
|
#include <any>
|
||
|
|
#include <chrono>
|
||
|
|
#include <functional>
|
||
|
|
#include <future>
|
||
|
|
#include <set>
|
||
|
|
|
||
|
|
namespace ais
|
||
|
|
{
|
||
|
|
enum class TaskStatus : int
|
||
|
|
{
|
||
|
|
UNKNOWN = 0,
|
||
|
|
UNASSIGNED, // not assigned to execute thread, added to avoid multi-assigned a task to different thread
|
||
|
|
NOT_START, // assigned but not start
|
||
|
|
RUNNING,
|
||
|
|
COMPLETED,
|
||
|
|
CANCELED,
|
||
|
|
FAILED,
|
||
|
|
SKIP,
|
||
|
|
};
|
||
|
|
|
||
|
|
// task class carry task function to support multi calling
|
||
|
|
class Task
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
Task() = default;
|
||
|
|
|
||
|
|
//============================================================================
|
||
|
|
// Method Description:
|
||
|
|
/// Individuals task which can be executing thread, use promise function to get task result
|
||
|
|
///
|
||
|
|
/// @param name: task name which can be individually assigned
|
||
|
|
/// @param func: task function
|
||
|
|
/// @param args: task arguments
|
||
|
|
/// @return Task
|
||
|
|
///
|
||
|
|
/// Task construct for non-void return functions
|
||
|
|
template <typename F, typename... A,
|
||
|
|
typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>,
|
||
|
|
typename = std::enable_if_t<!std::is_void_v<R>>>
|
||
|
|
Task(const std::string &_name, const F &func, const A &...args) : name(_name),
|
||
|
|
fun([func, args..., this]()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
taskPromise.set_value(task(args...));
|
||
|
|
}
|
||
|
|
catch (...)
|
||
|
|
{
|
||
|
|
taskPromise.set_exception(std::current_exception());
|
||
|
|
} })
|
||
|
|
{
|
||
|
|
result = taskPromise.get_future();
|
||
|
|
}
|
||
|
|
|
||
|
|
//============================================================================
|
||
|
|
// Method Description:
|
||
|
|
/// Individuals task which can be executing thread, use promise function to get task result
|
||
|
|
///
|
||
|
|
/// @param name: task name which can be individually assigned
|
||
|
|
/// @param func: task function
|
||
|
|
/// @param args: task arguments
|
||
|
|
/// @return Task
|
||
|
|
///
|
||
|
|
/// Task construct for void return functions
|
||
|
|
template <typename F, typename... A,
|
||
|
|
typename = std::enable_if_t<std::is_void_v<std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>>>
|
||
|
|
Task(const std::string &_name, const F &func, const A &...args) : name(_name),
|
||
|
|
fun([func, args..., this]()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
task(args...);
|
||
|
|
taskPromise.set_value(true);
|
||
|
|
}
|
||
|
|
catch (...)
|
||
|
|
{
|
||
|
|
taskPromise.set_exception(std::current_exception());
|
||
|
|
} })
|
||
|
|
{
|
||
|
|
result = taskPromise.get_future();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::shared_future<std::any> result;
|
||
|
|
|
||
|
|
// task name, used to identify task and search key in TaskManager
|
||
|
|
std::string name;
|
||
|
|
std::function<void()> fun;
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::promise<std::any> taskPromise;
|
||
|
|
};
|
||
|
|
|
||
|
|
// task node class included task and task extended properties,
|
||
|
|
// task manager will use task node as scheduling control
|
||
|
|
// 1 task can be scheduled in multi node for clone tasks.
|
||
|
|
struct TaskNode
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
std::shared_ptr<Task> p_task; // shared pointer to Task
|
||
|
|
|
||
|
|
// clone id to identify the different clone tasks
|
||
|
|
std::string clone_id = "";
|
||
|
|
|
||
|
|
TaskNode(std::shared_ptr<Task> _p_task,
|
||
|
|
const std::string &_clone_id = "") : p_task(_p_task), clone_id(_clone_id)
|
||
|
|
{
|
||
|
|
// when create a task node by p_task, make it unassigned.
|
||
|
|
status = TaskStatus::UNASSIGNED;
|
||
|
|
};
|
||
|
|
|
||
|
|
TaskStatus status = TaskStatus::UNKNOWN; // task status
|
||
|
|
|
||
|
|
bool is_async = false; // task is a async or not
|
||
|
|
std::string async_fetch_task_name = ""; // async fetch task name
|
||
|
|
|
||
|
|
// add_time will be setup while TaskNode have been constructed
|
||
|
|
std::chrono::system_clock::time_point add_time = std::chrono::system_clock::now();
|
||
|
|
|
||
|
|
// time for task start and completed.
|
||
|
|
std::chrono::system_clock::time_point start_time;
|
||
|
|
std::chrono::system_clock::time_point complete_time;
|
||
|
|
|
||
|
|
template <class T = std::chrono::seconds>
|
||
|
|
const uint64_t executed_spend_time()
|
||
|
|
{
|
||
|
|
return complete_time <= start_time ? 0 : (uint64_t)std::chrono::duration_cast<T>(complete_time - start_time).count();
|
||
|
|
}
|
||
|
|
|
||
|
|
void exec();
|
||
|
|
|
||
|
|
// set up callback functions for main task fun before/completed
|
||
|
|
void set_before_callback(std::function<void()> cb);
|
||
|
|
void set_after_callback(std::function<void()> cb);
|
||
|
|
void set_failed_callback(std::function<void()> cb);
|
||
|
|
|
||
|
|
std::thread::id executor_tid;
|
||
|
|
|
||
|
|
private:
|
||
|
|
// callback functions
|
||
|
|
std::function<void()> on_fun_before;
|
||
|
|
std::function<void()> on_fun_completed;
|
||
|
|
std::function<void()> on_fun_failed;
|
||
|
|
};
|
||
|
|
} // namespace ais
|