Flecs 多线程创建实体时触发 table.c 内部断言怎么办?
数据阿明
结论
这段代码使用了 Flecs 的 stage,但没有显式开启多线程只读阶段。对于应用自行管理线程、通过 get_stage(id) 写入的场景,应在线程启动前调用 readonly_begin(true),等所有线程结束后调用 readonly_end(),再检查实体。
get_stage(id) 会为线程提供独立的命令上下文,因此每个线程都应使用不同的 stage。set_stage_count(4) 配置了 4 个 stage,但这本身不会启动并行阶段。官方文档说明,stage 上的操作会排队,并在 stage 合并时应用到 world。Flecs Commands 文档
调整代码
int main() {
flecs::world world;
world.set_stage_count(4);
world.component<Position>();
world.component<Velocity>();
// 在线程启动前进入多线程只读阶段。
world.readonly_begin(true);
std::vector<std::thread> threads;
for (int i = 0; i < 4; i++) {
threads.emplace_back(worker, std::ref(world), i);
}
for (auto& t : threads) {
t.join();
}
// 结束只读阶段,并让 Flecs 处理各 stage 的排队操作。
world.readonly_end();
world.each<Position>([](flecs::entity e, Position& p) {
std::cout << "Entity " << e.id()
<< " Position(" << p.x << "," << p.y << ")\n";
});
}
readonly_begin(true) 应在线程启动前调用,readonly_end() 则应在线程全部 join() 后调用。Flecs 的 C++ world API 将 readonly_begin 定义为进入只读模式,并指出 merge() 只能在 staging 未启用时调用,例如 progress() 结束后或 readonly_end() 之后。Flecs world API
按这个生命周期使用时,通常不需要在 readonly_end() 后立即再调用 world.merge()。如果所用 Flecs 版本或具体工作流要求手动合并,应在 readonly_end() 之后调用,并核对该版本的 API 文档。
还要检查的地方
- 每个并行线程都必须使用自己的 stage。示例中的线程 ID 为
0到3,对应配置的 4 个 stage;不要让多个线程同时操作同一个 stage。 - 在线程启动前完成组件注册等 world 结构配置。只读阶段运行期间,避免从主 world 直接执行普通写操作。
- 这条断言说明内部表记录与表状态不一致,但仅凭日志无法确定唯一根因。如果按上述阶段边界调整后仍然崩溃,还需要确认 Flecs 的具体版本、完整调用栈,以及是否有其他线程同时访问 world 或 stage。
备注:内容仅供参考。
