Extra2D/include/core/scheduler.h

141 lines
3.2 KiB
C++

#pragma once
#include <types/base/types.h>
#include <types/ptr/ref_counted.h>
#include <types/ptr/intrusive_ptr.h>
#include <types/const/priority.h>
#include <atomic>
#include <vector>
#include <unordered_map>
#include <queue>
#include <mutex>
namespace extra2d {
using TimerHdl = uint32;
constexpr TimerHdl INVALID_HDL = 0;
/**
* @brief 定时器目标接口
*
* 实现此接口的对象可以接收 update 回调
*/
class TimerTarget {
public:
virtual ~TimerTarget() = default;
virtual void update(float dt) = 0;
};
/**
* @brief 定时器基类
*/
class Timer : public RefCounted {
public:
virtual ~Timer() = default;
virtual void update(float dt) = 0;
virtual void trigger() = 0;
bool isPaused() const { return paused_; }
bool isDone() const { return done_; }
TimerHdl hdl() const { return hdl_; }
void pause() { paused_ = true; }
void resume() { paused_ = false; }
void cancel() { done_ = true; }
protected:
Timer() = default;
float elapsed_ = -1.0f;
float interval_ = 0.0f;
float delay_ = 0.0f;
uint32 repeat_ = 0;
uint32 timesExecuted_ = 0;
bool useDelay_ = false;
bool runForever_ = false;
bool paused_ = false;
bool done_ = false;
TimerHdl hdl_ = INVALID_HDL;
friend class Scheduler;
};
/**
* @brief 调度器
*
* 基于标准库实现的线程安全调度器,支持定时器和 update 回调
*/
class Scheduler {
public:
using Cb = Fn<void(float)>;
using VoidCb = Fn<void()>;
static Scheduler& inst();
TimerHdl scheduleUpdate(TimerTarget* target, int pri = 0);
void unscheduleUpdate(TimerTarget* target);
TimerHdl schedule(Cb cb, float interval, uint32 repeat = 0, float delay = 0.0f);
TimerHdl scheduleOnce(VoidCb cb, float delay);
TimerHdl scheduleForever(Cb cb, float interval);
void unschedule(TimerHdl hdl);
void unscheduleAll();
void pause(TimerHdl hdl);
void resume(TimerHdl hdl);
void setTimeScale(float scale) { timeScale_ = scale; }
float timeScale() const { return timeScale_; }
void update(float dt);
void updateParallel(float dt);
bool isScheduled(TimerHdl hdl) const;
size_t count() const;
private:
Scheduler() = default;
struct UpdateEntry {
TimerTarget* target;
int pri;
bool paused;
bool markedForDel;
bool operator<(const UpdateEntry& o) const { return pri > o.pri; }
};
// 线程安全的优先队列包装
class SafePriorityQueue {
public:
void push(const UpdateEntry& entry);
bool pop(UpdateEntry& entry);
bool empty() const;
size_t size() const;
void clear();
private:
mutable std::mutex mutex_;
std::priority_queue<UpdateEntry> queue_;
};
std::vector<UpdateEntry> updates_;
std::unordered_map<TimerTarget*, size_t> updateIndex_;
mutable std::mutex updateIndexMutex_;
std::unordered_map<TimerHdl, Ptr<Timer>> timers_;
mutable std::mutex timersMutex_;
SafePriorityQueue updateQueue_;
std::atomic<TimerHdl> nextHdl_{1};
std::atomic<float> timeScale_{1.0f};
std::atomic<bool> locked_{false};
TimerHdl genHdl();
};
#define SCHED extra2d::Scheduler::inst()
} // namespace extra2d