fix: add thread safety for cave and river path mutexes

This commit is contained in:
2026-06-21 15:56:58 +08:00
parent 9a7fe1bfe9
commit 790f4a5aa4
8 changed files with 80 additions and 48 deletions

View File

@@ -17,11 +17,13 @@ public:
int cave_sum() const; int cave_sum() const;
float& cave_probability(); float& cave_probability();
std::shared_mutex& path_mutex();
private: private:
CaveHashMap m_paths; CaveHashMap m_paths;
unsigned m_seed = 0; unsigned m_seed = 0;
Random m_random; Random m_random;
float m_cave_probability = 0.035f; float m_cave_probability = 0.035f;
std::shared_mutex m_path_mutex;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -12,6 +12,7 @@ class RiverWorm {
public: public:
RiverWorm(); RiverWorm();
~RiverWorm();
RiverHashMap& paths(); RiverHashMap& paths();
void init(unsigned world_seed); void init(unsigned world_seed);
void reload(unsigned world_seed); void reload(unsigned world_seed);
@@ -21,12 +22,14 @@ public:
int river_sum() const; int river_sum() const;
float& river_probability(); float& river_probability();
std::shared_mutex& paths_mutex();
private: private:
RiverHashMap m_paths; RiverHashMap m_paths;
unsigned m_seed = 0; unsigned m_seed = 0;
Random m_random; Random m_random;
float m_probability = 0.01f; float m_probability = 0.01f;
std::shared_mutex m_paths_mutex;
}; };
}; // namespace Cubed }; // namespace Cubed

View File

@@ -104,6 +104,7 @@ private:
void submit_new_chunks(); void submit_new_chunks();
void poll_finished_chunks(); void poll_finished_chunks();
void wait_all_chunk_tasks();
public: public:
World(); World();

View File

@@ -48,7 +48,14 @@ public:
for (auto& w : m_workers) { for (auto& w : m_workers) {
w.request_stop(); w.request_stop();
} }
m_cv.notify_all(); 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) {

View File

@@ -63,5 +63,5 @@ void CaveCarver::cleanup_finished_caves() {
int CaveCarver::cave_sum() const { return m_paths.size(); } int CaveCarver::cave_sum() const { return m_paths.size(); }
float& CaveCarver::cave_probability() { return m_cave_probability; } float& CaveCarver::cave_probability() { return m_cave_probability; }
std::shared_mutex& CaveCarver::path_mutex() { return m_path_mutex; }
} // namespace Cubed } // namespace Cubed

View File

@@ -723,14 +723,17 @@ void ChunkGenerator::generate_cave() {
auto& paths = cave_carver.paths(); auto& paths = cave_carver.paths();
const auto& chunk_pos = m_chunk.chunk_pos(); const auto& chunk_pos = m_chunk.chunk_pos();
auto& blocks = m_chunk.blocks(); auto& blocks = m_chunk.blocks();
{
std::shared_lock lock(cave_carver.path_mutex());
for (auto& [id, path] : paths) { for (auto& [id, path] : paths) {
carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { carve_worm(path.points(), chunk_pos,
[&](int x, int y, int z) -> void {
int idx = Chunk::index(x, y, z); int idx = Chunk::index(x, y, z);
if (blocks[idx] == 7) if (blocks[idx] == 7)
return; return;
if (y < WORLD_SIZE_Y - 1 && blocks[Chunk::index(x, y + 1, z)] == 7) if (y < WORLD_SIZE_Y - 1 &&
blocks[Chunk::index(x, y + 1, z)] == 7)
return; return;
blocks[idx] = 0; blocks[idx] = 0;
}); });
@@ -738,6 +741,7 @@ void ChunkGenerator::generate_cave() {
path.clear_chunk(chunk_pos); path.clear_chunk(chunk_pos);
} }
} }
}
} }
void ChunkGenerator::generate_river() { void ChunkGenerator::generate_river() {
@@ -746,16 +750,19 @@ void ChunkGenerator::generate_river() {
auto& paths = river_worm.paths(); auto& paths = river_worm.paths();
const auto& chunk_pos = m_chunk.chunk_pos(); const auto& chunk_pos = m_chunk.chunk_pos();
auto& blocks = m_chunk.blocks(); auto& blocks = m_chunk.blocks();
bool is_river = false; bool is_river = false;
{
std::shared_lock lock(river_worm.paths_mutex());
for (auto& [id, path] : paths) { for (auto& [id, path] : paths) {
if ((m_chunk.biome() == BiomeType::DESERT) || if ((m_chunk.biome() == BiomeType::DESERT) ||
(m_chunk.biome() == BiomeType::OCEAN)) { (m_chunk.biome() == BiomeType::OCEAN)) {
if (!m_chunk.is_temp_chunk()) {
path.clear_chunk(chunk_pos); path.clear_chunk(chunk_pos);
}
continue; continue;
} }
carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { carve_worm(path.points(), chunk_pos,
[&](int x, int y, int z) -> void {
int idx = Chunk::index(x, y, z); int idx = Chunk::index(x, y, z);
if (y > SEA_LEVEL) { if (y > SEA_LEVEL) {
blocks[idx] = 0; blocks[idx] = 0;
@@ -771,6 +778,7 @@ void ChunkGenerator::generate_river() {
path.clear_chunk(chunk_pos); path.clear_chunk(chunk_pos);
} }
} }
}
if (is_river) { if (is_river) {
m_chunk.biome(RIVER); m_chunk.biome(RIVER);

View File

@@ -4,7 +4,7 @@
namespace Cubed { namespace Cubed {
RiverWorm::RiverWorm() {} RiverWorm::RiverWorm() {}
RiverWorm::~RiverWorm() {}
RiverWorm::RiverHashMap& RiverWorm::paths() { return m_paths; } RiverWorm::RiverHashMap& RiverWorm::paths() { return m_paths; }
void RiverWorm::init(unsigned world_seed) { void RiverWorm::init(unsigned world_seed) {
@@ -60,5 +60,6 @@ void RiverWorm::cleanup_finished_rivers() {
int RiverWorm::river_sum() const { return m_paths.size(); } int RiverWorm::river_sum() const { return m_paths.size(); }
float& RiverWorm::river_probability() { return m_probability; } float& RiverWorm::river_probability() { return m_probability; }
std::shared_mutex& RiverWorm::paths_mutex() { return m_paths_mutex; }
} // namespace Cubed } // namespace Cubed

View File

@@ -21,6 +21,9 @@ World::World() {}
World::~World() { World::~World() {
stop_gen_thread(); stop_gen_thread();
stop_server_thread(); stop_server_thread();
wait_all_chunk_tasks();
m_gen_thread_pool.reset();
m_chunks.clear(); m_chunks.clear();
{ {
std::lock_guard lk(m_delete_vbo_mutex); std::lock_guard lk(m_delete_vbo_mutex);
@@ -38,6 +41,12 @@ World::~World() {
} }
} }
void World::wait_all_chunk_tasks() {
for (auto& [pos, task] : new_chunks) {
task.future.get();
}
}
bool World::can_move(const AABB& player_box) const { return true; } bool World::can_move(const AABB& player_box) const { return true; }
const std::optional<LookBlock>& const std::optional<LookBlock>&
@@ -158,21 +167,26 @@ void World::gen_chunks_internal() {
new_chunks.emplace(pos, Chunk(*this, pos)); new_chunks.emplace(pos, Chunk(*this, pos));
} }
auto t1 = system_clock::now(); auto t1 = system_clock::now();
parallel_do(*m_gen_thread_pool, temp_neighbor.begin(), temp_neighbor.end(), {
m_gen_thread_pool->thread_sum(), std::scoped_lock lock{m_cave_carcer.path_mutex(),
m_river_worm.paths_mutex()};
parallel_do(*m_gen_thread_pool, temp_neighbor.begin(),
temp_neighbor.end(), m_gen_thread_pool->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();
m_cave_carcer.try_to_add_path(pos, chunk.seed()); m_cave_carcer.try_to_add_path(pos, chunk.seed());
m_river_worm.try_to_add_path(pos, chunk.seed()); m_river_worm.try_to_add_path(pos, chunk.seed());
}); });
m_cave_carcer.cleanup_finished_caves();
m_river_worm.cleanup_finished_rivers();
}
auto t2 = system_clock::now(); auto t2 = system_clock::now();
Logger::info("Temp Neighbor Add Path Consum {}", Logger::info("Temp Neighbor Add Path Consum {}",
duration_cast<milliseconds>(t2 - t1)); duration_cast<milliseconds>(t2 - t1));
m_chunk_gen_fraction = 0.9f; m_chunk_gen_fraction = 0.9f;
m_cave_carcer.cleanup_finished_caves();
m_river_worm.cleanup_finished_rivers();
m_chunk_gen_fraction = 1.0f; m_chunk_gen_fraction = 1.0f;
submit_new_chunks(); submit_new_chunks();
m_chunk_gen_finished = true; m_chunk_gen_finished = true;
@@ -209,10 +223,6 @@ void World::compute_required_chunks(ChunkPosSet& required_chunks,
for (int dz = -radius; dz <= radius; ++dz) { for (int dz = -radius; dz <= radius; ++dz) {
if (dx * dx + dz * dz <= r2) { if (dx * dx + dz * dz <= r2) {
ChunkPos pos{chunk_x + dx, chunk_z + dz}; ChunkPos pos{chunk_x + dx, chunk_z + dz};
auto it = required_chunks.find(pos);
if (it != required_chunks.end()) {
continue;
}
temp_neighbor.emplace_back(pos, Chunk(*this, pos)); temp_neighbor.emplace_back(pos, Chunk(*this, pos));
} }
} }