Files
Frostbite2D/Frostbite2D/include/frostbite2D/core/task_system.h
Lenheart 42e5579cc3 feat: 添加任务系统并实现异步资源加载功能
添加任务系统(TaskSystem)支持多线程任务处理和主线程回调
扩展Actor类添加更新监听器功能
新增GameWorld和GameTown场景类
添加多种混合模式(BlendMode)支持
实现异步资源加载界面和流程
2026-04-01 09:02:13 +08:00

143 lines
4.3 KiB
C++

#pragma once
#include <atomic>
#include <condition_variable>
#include <exception>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits>
#include <utility>
#include <vector>
#include <frostbite2D/types/type_alias.h>
namespace frostbite2D {
struct TaskSystemConfig {
uint32 workerCount = 0;
uint32 maxMainThreadCallbacksPerFrame = 0;
uint32 threadStackSize = 0;
};
class TaskSystem {
public:
static TaskSystem& get();
TaskSystem(const TaskSystem&) = delete;
TaskSystem& operator=(const TaskSystem&) = delete;
bool init(const TaskSystemConfig& config = {});
void shutdown();
bool isInitialized() const { return initialized_; }
bool isMainThread() const;
size_t workerCount() const;
uint32 maxMainThreadCallbacksPerFrame() const;
template <typename F>
void post(F&& task) {
enqueueWorkerTask(Function<void()>(std::forward<F>(task)));
}
template <typename F>
auto submit(F&& task) -> std::future<std::invoke_result_t<F>> {
using Result = std::invoke_result_t<F>;
auto packagedTask =
std::make_shared<std::packaged_task<Result()>>(std::forward<F>(task));
std::future<Result> future = packagedTask->get_future();
enqueueWorkerTask([packagedTask]() mutable { (*packagedTask)(); });
return future;
}
template <typename F>
void postToMainThread(F&& callback) {
enqueueMainThreadTask(Function<void()>(std::forward<F>(callback)));
}
template <typename Task, typename OnComplete>
void submitThen(Task&& task, OnComplete&& onComplete) {
using Result = std::invoke_result_t<Task>;
using Storage = std::decay_t<Result>;
auto taskFn = std::make_shared<std::decay_t<Task>>(std::forward<Task>(task));
auto completeFn =
std::make_shared<std::decay_t<OnComplete>>(std::forward<OnComplete>(onComplete));
enqueueWorkerTask([this, taskFn, completeFn]() mutable {
try {
if constexpr (std::is_void_v<Result>) {
std::invoke(*taskFn);
enqueueMainThreadTask([completeFn]() mutable { std::invoke(*completeFn); });
} else {
auto result = std::make_shared<Storage>(std::invoke(*taskFn));
enqueueMainThreadTask([completeFn, result]() mutable {
std::invoke(*completeFn, std::move(*result));
});
}
} catch (...) {
logUnhandledTaskException(std::current_exception());
}
});
}
template <typename Task, typename OnComplete, typename OnError>
void submitThen(Task&& task, OnComplete&& onComplete, OnError&& onError) {
using Result = std::invoke_result_t<Task>;
using Storage = std::decay_t<Result>;
auto taskFn = std::make_shared<std::decay_t<Task>>(std::forward<Task>(task));
auto completeFn =
std::make_shared<std::decay_t<OnComplete>>(std::forward<OnComplete>(onComplete));
auto errorFn =
std::make_shared<std::decay_t<OnError>>(std::forward<OnError>(onError));
enqueueWorkerTask([this, taskFn, completeFn, errorFn]() mutable {
try {
if constexpr (std::is_void_v<Result>) {
std::invoke(*taskFn);
enqueueMainThreadTask([completeFn]() mutable { std::invoke(*completeFn); });
} else {
auto result = std::make_shared<Storage>(std::invoke(*taskFn));
enqueueMainThreadTask([completeFn, result]() mutable {
std::invoke(*completeFn, std::move(*result));
});
}
} catch (...) {
auto error = std::make_shared<std::exception_ptr>(std::current_exception());
enqueueMainThreadTask([errorFn, error]() mutable { std::invoke(*errorFn, *error); });
}
});
}
void drainMainThreadTasks(uint32 maxTasks = 0);
private:
TaskSystem() = default;
~TaskSystem();
void enqueueWorkerTask(Function<void()> task);
void enqueueMainThreadTask(Function<void()> task);
size_t resolveWorkerCount(uint32 requestedCount) const;
static void logUnhandledTaskException(std::exception_ptr error);
TaskSystemConfig config_;
std::vector<std::thread> workers_;
std::queue<Function<void()>> workerTasks_;
std::queue<Function<void()>> mainThreadTasks_;
mutable std::mutex workerMutex_;
mutable std::mutex mainThreadMutex_;
std::condition_variable workerCondition_;
std::atomic<bool> initialized_ = false;
std::atomic<bool> acceptingTasks_ = false;
std::thread::id mainThreadId_;
};
} // namespace frostbite2D