3D优化完成
This commit is contained in:
@@ -38,21 +38,6 @@ Nanoseconds fps_period(double fps) {
|
||||
struct Frame_Scheduler::Timer::State {
|
||||
enum struct Mode : std::uint8_t { stopped, once, periodic };
|
||||
|
||||
not_null<Frame_Scheduler::Private*> owner;
|
||||
std::uint64_t id{};
|
||||
Handler handler{};
|
||||
std::atomic_bool alive{true};
|
||||
Mode mode{Mode::stopped}; /* 仅 Scheduler thread 访问。 */
|
||||
Nanoseconds period{}; /* 仅 Scheduler thread 访问。 */
|
||||
Scheduler_Clock::time_point next_deadline{}; /* 真实 deadline,不按 tick 累积。 */
|
||||
TimerEvent<std::function<void()>> event;
|
||||
|
||||
State(not_null<Frame_Scheduler::Private*> value_owner,
|
||||
std::uint64_t value_id,
|
||||
Handler value_handler);
|
||||
};
|
||||
|
||||
struct Frame_Scheduler::Private {
|
||||
enum struct Command_Type : std::uint8_t {
|
||||
periodic,
|
||||
once,
|
||||
@@ -62,14 +47,48 @@ struct Frame_Scheduler::Private {
|
||||
};
|
||||
struct Command {
|
||||
Command_Type type{};
|
||||
std::shared_ptr<Timer::State> state{};
|
||||
std::shared_ptr<State> state{};
|
||||
Nanoseconds value{};
|
||||
};
|
||||
struct Command_Ingress {
|
||||
moodycamel::BlockingConcurrentQueue<Command> commands{256};
|
||||
std::atomic_bool accepting{true};
|
||||
|
||||
[[nodiscard]] bool enqueue(Command command) {
|
||||
if (command.type != Command_Type::destroy &&
|
||||
command.type != Command_Type::stop &&
|
||||
!accepting.load(std::memory_order_acquire))
|
||||
return false;
|
||||
return commands.enqueue(std::move(command));
|
||||
}
|
||||
};
|
||||
|
||||
not_null<Frame_Scheduler::Private*> owner;
|
||||
std::weak_ptr<Command_Ingress> ingress;
|
||||
std::uint64_t id{};
|
||||
Handler handler{};
|
||||
std::atomic_bool alive{true};
|
||||
Mode mode{Mode::stopped}; /* 仅 Scheduler thread 访问。 */
|
||||
Nanoseconds period{}; /* 仅 Scheduler thread 访问。 */
|
||||
Scheduler_Clock::time_point next_deadline{}; /* 真实 deadline,不按 tick 累积。 */
|
||||
TimerEvent<std::function<void()>> event;
|
||||
|
||||
State(not_null<Frame_Scheduler::Private*> value_owner,
|
||||
const std::shared_ptr<Command_Ingress>& value_ingress,
|
||||
std::uint64_t value_id,
|
||||
Handler value_handler);
|
||||
};
|
||||
|
||||
struct Frame_Scheduler::Private {
|
||||
using Command_Type = Timer::State::Command_Type;
|
||||
using Command = Timer::State::Command;
|
||||
using Command_Ingress = Timer::State::Command_Ingress;
|
||||
|
||||
std::shared_ptr<Command_Ingress> ingress{
|
||||
std::make_shared<Command_Ingress>()};
|
||||
TimerWheel wheel{};
|
||||
Scheduler_Clock::time_point origin{Scheduler_Clock::now()};
|
||||
Scheduler_Clock::time_point last_advance{origin};
|
||||
moodycamel::BlockingConcurrentQueue<Command> commands{256};
|
||||
std::atomic_uint64_t next_id{1};
|
||||
std::atomic_bool stopping{};
|
||||
std::jthread thread{};
|
||||
@@ -77,19 +96,21 @@ struct Frame_Scheduler::Private {
|
||||
Private() : thread([this](std::stop_token stop) { run(stop); }) {}
|
||||
|
||||
~Private() {
|
||||
ingress->accepting.store(false, std::memory_order_release);
|
||||
stopping.store(true, std::memory_order_release);
|
||||
thread.request_stop();
|
||||
enqueue({Command_Type::stop});
|
||||
}
|
||||
|
||||
void enqueue(Command command) {
|
||||
if (!commands.enqueue(std::move(command))) std::terminate();
|
||||
if (!ingress->enqueue(std::move(command))) std::terminate();
|
||||
}
|
||||
|
||||
std::shared_ptr<Timer::State> make_timer(Handler handler) {
|
||||
if (!handler) throw std::invalid_argument("frame scheduler timer handler is empty");
|
||||
const auto id = next_id.fetch_add(1, std::memory_order_relaxed);
|
||||
auto state = std::make_shared<Timer::State>(this, id, std::move(handler));
|
||||
auto state = std::make_shared<Timer::State>(
|
||||
this, ingress, id, std::move(handler));
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -152,7 +173,7 @@ struct Frame_Scheduler::Private {
|
||||
|
||||
void process_commands(Scheduler_Clock::time_point now) {
|
||||
Command command;
|
||||
while (commands.try_dequeue(command)) {
|
||||
while (ingress->commands.try_dequeue(command)) {
|
||||
process_command(std::move(command), now);
|
||||
now = Scheduler_Clock::now();
|
||||
}
|
||||
@@ -221,7 +242,7 @@ struct Frame_Scheduler::Private {
|
||||
const auto deadline = last_advance +
|
||||
Frame_Scheduler::tick_duration * static_cast<std::int64_t>(next);
|
||||
Command command;
|
||||
if (commands.wait_dequeue_timed(
|
||||
if (ingress->commands.wait_dequeue_timed(
|
||||
command, std::max(deadline - Scheduler_Clock::now(),
|
||||
Scheduler_Clock::duration::zero())))
|
||||
process_command(std::move(command), Scheduler_Clock::now());
|
||||
@@ -234,9 +255,12 @@ struct Frame_Scheduler::Private {
|
||||
};
|
||||
|
||||
Frame_Scheduler::Timer::State::State(
|
||||
not_null<Frame_Scheduler::Private*> value_owner, std::uint64_t value_id,
|
||||
not_null<Frame_Scheduler::Private*> value_owner,
|
||||
const std::shared_ptr<Command_Ingress>& value_ingress,
|
||||
std::uint64_t value_id,
|
||||
Handler value_handler)
|
||||
: owner(value_owner), id(value_id), handler(std::move(value_handler)),
|
||||
: owner(value_owner), ingress(value_ingress), id(value_id),
|
||||
handler(std::move(value_handler)),
|
||||
event([this] {
|
||||
owner->fire(*this);
|
||||
}) {}
|
||||
@@ -259,7 +283,10 @@ Frame_Scheduler::Timer::Timer(std::shared_ptr<State> state) noexcept
|
||||
Frame_Scheduler::Timer::~Timer() noexcept {
|
||||
if (!state_) return;
|
||||
state_->alive.store(false, std::memory_order_release);
|
||||
state_->owner->enqueue({Private::Command_Type::destroy, state_, {}});
|
||||
const auto ingress = state_->ingress.lock();
|
||||
if (ingress && !ingress->enqueue(
|
||||
{Private::Command_Type::destroy, state_, {}}))
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
Frame_Scheduler::Timer::Timer(Timer&& other) noexcept
|
||||
@@ -279,19 +306,31 @@ void Frame_Scheduler::Timer::start_periodic(double fps) {
|
||||
return;
|
||||
}
|
||||
state_->alive.store(true, std::memory_order_release);
|
||||
state_->owner->enqueue({Private::Command_Type::periodic, state_, fps_period(fps)});
|
||||
const auto ingress = state_->ingress.lock();
|
||||
if (!ingress || !ingress->enqueue(
|
||||
{Private::Command_Type::periodic, state_, fps_period(fps)})) {
|
||||
state_->alive.store(false, std::memory_order_release);
|
||||
throw std::runtime_error("frame scheduler is stopping");
|
||||
}
|
||||
}
|
||||
|
||||
void Frame_Scheduler::Timer::start_once(std::chrono::nanoseconds delay) {
|
||||
if (!state_) throw std::logic_error("frame scheduler timer is empty");
|
||||
state_->alive.store(true, std::memory_order_release);
|
||||
state_->owner->enqueue({Private::Command_Type::once, state_, delay});
|
||||
const auto ingress = state_->ingress.lock();
|
||||
if (!ingress || !ingress->enqueue(
|
||||
{Private::Command_Type::once, state_, delay})) {
|
||||
state_->alive.store(false, std::memory_order_release);
|
||||
throw std::runtime_error("frame scheduler is stopping");
|
||||
}
|
||||
}
|
||||
|
||||
void Frame_Scheduler::Timer::cancel() noexcept {
|
||||
if (!state_ || !state_->owner) return;
|
||||
if (!state_) return;
|
||||
state_->alive.store(false, std::memory_order_release);
|
||||
state_->owner->enqueue({Private::Command_Type::cancel, state_, {}});
|
||||
const auto ingress = state_->ingress.lock();
|
||||
if (ingress) static_cast<void>(ingress->enqueue(
|
||||
{Private::Command_Type::cancel, state_, {}}));
|
||||
}
|
||||
|
||||
bool Frame_Scheduler::Timer::valid() const noexcept {
|
||||
|
||||
Reference in New Issue
Block a user