125 lines
2.9 KiB
C++
125 lines
2.9 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 <tbb/concurrent_hash_map.h>
|
|
#include <tbb/concurrent_priority_queue.h>
|
|
#include <tbb/parallel_for.h>
|
|
#include <tbb/blocked_range.h>
|
|
#include <atomic>
|
|
#include <vector>
|
|
|
|
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 调度器
|
|
*
|
|
* 基于 TBB 实现的线程安全调度器,支持定时器和 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; }
|
|
};
|
|
|
|
std::vector<UpdateEntry> updates_;
|
|
tbb::concurrent_hash_map<TimerTarget*, size_t> updateIndex_;
|
|
tbb::concurrent_hash_map<TimerHdl, Ptr<Timer>> timers_;
|
|
tbb::concurrent_priority_queue<UpdateEntry> 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
|