feat: add JobSystem

This commit is contained in:
2026-10-24 00:59:22 +02:00
parent b798ed0378
commit 9c5a97cfbd
7 changed files with 502 additions and 1 deletions
@@ -0,0 +1,95 @@
#ifndef DESTRUM_JOBSYSTEM_H
#define DESTRUM_JOBSYSTEM_H
#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <deque>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <thread>
#include <type_traits>
#include <vector>
#include <destrum/Singleton.h>
enum class JobPriority {
High,
Low,
};
class JobCounter {
public:
JobCounter() = default;
JobCounter(const JobCounter&) = delete;
JobCounter& operator=(const JobCounter&) = delete;
[[nodiscard]] bool IsDone() const { return m_Pending.load(std::memory_order_acquire) == 0; }
private:
friend class JobSystem;
std::atomic<int> m_Pending{0};
};
struct JobDispatchArgs {
std::uint32_t index{0};
std::uint32_t groupIndex{0};
};
class JobSystem final : public Singleton<JobSystem> {
public:
friend class Singleton<JobSystem>;
using Job = std::function<void()>;
~JobSystem() override;
// 0 workers picks hardware_concurrency - 1
void Init(std::uint32_t workerCount = 0);
void Shutdown();
[[nodiscard]] bool IsRunning() const { return !m_Workers.empty(); }
[[nodiscard]] std::uint32_t GetWorkerCount() const { return static_cast<std::uint32_t>(m_Workers.size()); }
void Execute(JobCounter& counter, Job job, JobPriority priority = JobPriority::High);
void Dispatch(JobCounter& counter, std::uint32_t count, std::uint32_t groupSize,
std::function<void(JobDispatchArgs)> job);
void Wait(JobCounter& counter);
template <typename F>
auto Async(F&& fn) -> std::future<std::invoke_result_t<std::decay_t<F>>>
{
using Result = std::invoke_result_t<std::decay_t<F>>;
auto task = std::make_shared<std::packaged_task<Result()>>(std::forward<F>(fn));
auto future = task->get_future();
Submit([task] { (*task)(); }, JobPriority::Low);
return future;
}
void RunOnMainThread(Job job);
void DrainMainThreadQueue();
private:
JobSystem() = default;
void Submit(Job job, JobPriority priority);
bool TryPopLocked(Job& job, bool& isLow);
[[nodiscard]] bool CanTakeLowLocked() const;
bool TryRunHighJob();
void WorkerLoop(std::uint32_t index);
std::vector<std::thread> m_Workers;
std::mutex m_Mutex;
std::condition_variable m_WorkAvailable;
std::deque<Job> m_HighQueue;
std::deque<Job> m_LowQueue;
std::uint32_t m_ActiveLowJobs{0};
std::uint32_t m_MaxActiveLowJobs{1};
bool m_Stopping{false};
std::mutex m_MainThreadMutex;
std::vector<Job> m_MainThreadQueue;
};
#endif // DESTRUM_JOBSYSTEM_H