无法通过多线程启动两个RayLib窗口的原因及解决方法
我用RayLib开发时写了创建窗口的代码,单独运行或单线程启动(比如std::thread game1 (&start_window, "test");)能正常创建窗口,但多线程启动两个窗口(std::thread game1 (&start_window, "test"); std::thread game2 (&start_window, "test 2");)时,完全没有窗口弹出。想知道原因是什么?能不能用多线程启动两个RayLib窗口?如果可以,该怎么实现?
相关代码
void start_window(std::string windowName){ InitWindow(800, 450, windowName.c_str()); SetTargetFPS(60); rlFPCamera cam; cam.Setup(45,Vector3{ 1, 0, 0 }); cam.SetCameraPosition((Vector3){1.0f, 500.0f, 1.0f}); cam.MoveSpeed.z = 100; cam.MoveSpeed.x = 100; cam.FarPlane = 5000; Material matDefault = LoadMaterialDefault(); Material matRed = LoadMaterialDefault(); Material matGreen = LoadMaterialDefault(); matDefault.maps[MATERIAL_MAP_DIFFUSE].color = BLUE; matRed.maps[MATERIAL_MAP_DIFFUSE].color = RED; matGreen.maps[MATERIAL_MAP_DIFFUSE].color = GREEN; Model cube = LoadModelFromMesh(GenMeshCube(5,5,5)); int width = 3072; int height = 3072; // Dynamic memory allocation to store pixels data (Color type) Color *pixels = (Color *)malloc(width*height*sizeof(Color)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (((x/16+y/16)/1)%2 == 0) pixels[y*width + x] = WHITE; else pixels[y*width + x] = BLUE; } } Image checkedIm = { .data = pixels, // We can assign pixels directly to data .width = width, .height = height, .mipmaps = 1, .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, }; Texture2D checked = LoadTextureFromImage(checkedIm); Model terrain = LoadModel("Resources/Terrains/TestingGround.obj"); terrain.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = checked; Vector3 cubePosition = {2.50f, 3.0f, 2.50f}; UnloadImage(checkedIm); while (!WindowShouldClose()) // Detect window close button or ESC key { cam.Update(); float offsetThisFrame = 100.0f*GetFrameTime(); BeginDrawing(); ClearBackground(SKYBLUE); cam.BeginMode3D(); DrawGrid(1000, 1.0f); if (IsKeyDown(KEY_SPACE)) { cam.SetCameraPosition((Vector3){cam.GetCameraPosition().x, cam.GetCameraPosition().y+offsetThisFrame, cam.GetCameraPosition().z}); } else if (IsKeyDown(KEY_Z)) { cam.SetCameraPosition((Vector3){cam.GetCameraPosition().x, cam.GetCameraPosition().y-offsetThisFrame, cam.GetCameraPosition().z}); } if (IsKeyPressed(KEY_SPACE)) { cubePosition = {cubePosition.x, cubePosition.y + 5, cubePosition.z}; } VibraniumEngine::DrawModel(cube, (Vector3){50.30f, 12.32f, 40.7f}, 1, RED); VibraniumEngine::DrawModel(cube, (Vector3){68.8f, 8.8f, 74.7f}, 1, RED); VibraniumEngine::DrawModel(cube, (Vector3){15.52f, 11.65f, 84.51f}, 1, RED); VibraniumEngine::DrawModel(cube, cubePosition, 1, BLUE); DrawModelEx(terrain, (Vector3){0.0f, 0.0f, 0.0f},(Vector3){0.0f, 0.0f, 0.0f}, 0.0f,(Vector3){1.0f, 1.0f, 1.0f}, WHITE); EndMode3D(); DrawFPS( 10, 10); DrawText("Press H to hide the Map Window.", 10, 32, 12, GREEN); DrawText(TextFormat("Camera Pos: X: %3.2fY: %3.2f Z: %3.2f", cam.GetCameraPosition().x * -1, cam.GetCameraPosition().y, cam.GetCameraPosition().z), 10, 52, 12, BLACK); EndDrawing(); } UnloadModel(cube); CloseWindow(); }
问题原因
RayLib默认单窗口模式依赖全局状态(比如OpenGL上下文、输入处理逻辑等),多线程直接调用InitWindow会触发资源竞争和上下文冲突,系统无法正确初始化多个窗口的渲染环境,最终导致窗口无法显示。
实现多窗口的正确方式
RayLib支持多窗口,但需要启用多窗口模式,且每个窗口的生命周期必须完全隔离在各自线程中,具体步骤如下:
编译时启用多窗口支持
编译RayLib时必须定义RAYLIB_MULTI_WINDOW宏:- 自行编译库:在CMake中添加
-DRAYLIB_MULTI_WINDOW=ON,或在编译选项中加入-DRAYLIB_MULTI_WINDOW - 使用预编译库:选择带多窗口支持的版本
- 自行编译库:在CMake中添加
线程逻辑完全隔离
每个线程必须独立完成窗口初始化、渲染循环、资源销毁流程,绝对不能跨线程调用RayLib的窗口/渲染相关函数。你的现有代码结构已经符合单线程隔离要求,只需确保宏定义正确。主线程等待子线程完成
启动线程后必须调用join(),避免主线程提前退出导致子线程资源未正确释放,示例代码:std::thread game1(&start_window, "test"); std::thread game2(&start_window, "test 2"); game1.join(); game2.join();适配平台限制
部分平台(如Windows)对多线程创建窗口有额外限制,RayLib的WindowShouldClose()、BeginDrawing()/EndDrawing()已经内置处理了消息循环,只需保证线程不被阻塞即可。
验证流程
确认以下几点后即可正常启动两个独立窗口:
- 编译时已开启
RAYLIB_MULTI_WINDOW宏 - 每个线程独立执行
InitWindow、渲染循环、CloseWindow - 主线程等待所有子线程执行完毕
内容的提问来源于stack exchange,提问作者Venelin

