feat(world): add dynamic thread pool resizing

This commit is contained in:
2026-06-21 16:36:15 +08:00
parent 2386d98217
commit 34d9439466
4 changed files with 46 additions and 25 deletions

View File

@@ -26,7 +26,7 @@ constexpr float DEFAULT_G = 22.5f;
constexpr int SIZE_X = CHUNK_SIZE; constexpr int SIZE_X = CHUNK_SIZE;
constexpr int SIZE_Y = WORLD_SIZE_Y; constexpr int SIZE_Y = WORLD_SIZE_Y;
constexpr int SIZE_Z = CHUNK_SIZE; constexpr int SIZE_Z = CHUNK_SIZE;
constexpr int RESERVED_THREADS = 3;
constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1},
{1, 1}, {-1, 1}, {1, -1}, {-1, -1}}; {1, 1}, {-1, 1}, {1, -1}, {-1, -1}};

View File

@@ -58,7 +58,7 @@ private:
std::thread m_gen_thread; std::thread m_gen_thread;
std::thread m_server_thread; std::thread m_server_thread;
std::unique_ptr<ThreadPool> m_gen_thread_pool; std::atomic<std::shared_ptr<ThreadPool>> m_gen_thread_pool;
std::stop_source m_server_stop_source; std::stop_source m_server_stop_source;
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
@@ -159,6 +159,8 @@ public:
bool is_tick_running() const; bool is_tick_running() const;
void tick_running(bool run); void tick_running(bool run);
void change_pool_threads(int threads);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -43,20 +43,7 @@ public:
}); });
} }
} }
~ThreadPool() { ~ThreadPool() { stop(); }
m_stopping = true;
for (auto& w : m_workers) {
w.request_stop();
}
m_cv.notify_all();
for (auto& w : m_workers) {
if (w.joinable()) {
w.join();
}
}
}
template <typename F> auto enqueue(F&& f) { template <typename F> auto enqueue(F&& f) {
using R = std::invoke_result_t<F>; using R = std::invoke_result_t<F>;
@@ -74,6 +61,20 @@ public:
m_cv.notify_one(); m_cv.notify_one();
return fut; return fut;
} }
void stop() {
m_stopping = true;
for (auto& w : m_workers) {
w.request_stop();
}
m_cv.notify_all();
for (auto& w : m_workers) {
if (w.joinable()) {
w.join();
}
}
}
size_t thread_sum() const { return m_thread_sum.load(); } size_t thread_sum() const { return m_thread_sum.load(); }
}; };

View File

@@ -22,7 +22,11 @@ World::~World() {
stop_gen_thread(); stop_gen_thread();
stop_server_thread(); stop_server_thread();
wait_all_chunk_tasks(); wait_all_chunk_tasks();
m_gen_thread_pool.reset(); auto pool_ptr = m_gen_thread_pool.load();
if (pool_ptr) {
pool_ptr->stop();
}
m_gen_thread_pool.store(nullptr);
m_chunks.clear(); m_chunks.clear();
{ {
@@ -86,10 +90,7 @@ void World::init_world() {
m_river_worm.init(ChunkGenerator::seed()); m_river_worm.init(ChunkGenerator::seed());
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4); m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
int max_thread = std::thread::hardware_concurrency(); int max_thread = std::thread::hardware_concurrency();
int used_thread = std::max(max_thread - 3, 1); change_pool_threads(max_thread - RESERVED_THREADS);
Logger::info("Max Support Thread is {}, use {} threads to gen", max_thread,
used_thread);
m_gen_thread_pool = std::make_unique<ThreadPool>(used_thread);
auto t1 = std::chrono::system_clock::now(); auto t1 = std::chrono::system_clock::now();
@@ -170,8 +171,12 @@ void World::gen_chunks_internal() {
{ {
std::scoped_lock lock{m_cave_carcer.path_mutex(), std::scoped_lock lock{m_cave_carcer.path_mutex(),
m_river_worm.paths_mutex()}; m_river_worm.paths_mutex()};
parallel_do(*m_gen_thread_pool, temp_neighbor.begin(), auto pool_ptr = m_gen_thread_pool.load();
temp_neighbor.end(), m_gen_thread_pool->thread_sum(), if (!pool_ptr) {
return;
}
parallel_do(*pool_ptr, temp_neighbor.begin(), temp_neighbor.end(),
pool_ptr->thread_sum(),
[this](std::pair<ChunkPos, Chunk>& new_chunk) { [this](std::pair<ChunkPos, Chunk>& new_chunk) {
auto& [pos, chunk] = new_chunk; auto& [pos, chunk] = new_chunk;
chunk.gen_phase_one(); chunk.gen_phase_one();
@@ -251,10 +256,14 @@ void World::sync_and_collect_missing_chunks(
void World::submit_new_chunks() { void World::submit_new_chunks() {
std::lock_guard lock(m_new_chunk_mutex); std::lock_guard lock(m_new_chunk_mutex);
auto pool_ptr = m_gen_thread_pool.load();
if (!pool_ptr) {
return;
}
for (auto& [pos, task] : new_chunks) { for (auto& [pos, task] : new_chunks) {
if (!task.future.valid()) { if (!task.future.valid()) {
task.future = m_gen_thread_pool->enqueue( task.future =
[&task]() { task.chunk.gen_chunk(); }); pool_ptr->enqueue([&task]() { task.chunk.gen_chunk(); });
} }
} }
} }
@@ -648,4 +657,13 @@ void World::per_tick_time(int ms) { m_per_tick_time = ms; }
bool World::is_tick_running() const { return m_tick_running.load(); } bool World::is_tick_running() const { return m_tick_running.load(); }
void World::tick_running(bool run) { m_tick_running = run; } void World::tick_running(bool run) { m_tick_running = run; }
void World::change_pool_threads(int threads) {
int max_thread = std::thread::hardware_concurrency();
if (max_thread < 1) {
max_thread = 4;
}
int used_thread = std::clamp(threads, 1, max_thread);
Logger::info("Create New Thread Pool Use {} Threads", used_thread);
m_gen_thread_pool.store(std::make_shared<ThreadPool>(used_thread));
}
} // namespace Cubed } // namespace Cubed