Windows下ONNX Runtime推理时CWaitCursor不旋转的解决方法咨询
解决方案:ONNX Runtime推理时保持等待光标旋转
1. 将ORT推理移至后台线程执行
这是最根本的解决思路——把耗时的推理任务从主线程剥离,让主线程专注处理UI消息(包括光标更新)。
VC++示例代码:
#include <thread> #include <windows.h> // 标记推理状态 bool g_inferenceCompleted = false; // ORT会话对象(若会话不支持多线程,建议在后台线程内创建) Ort::Session* g_ortSession = nullptr; // 后台推理线程函数 void RunInferenceThread(const std::vector<float>& inputData) { // 执行ORT推理逻辑 // ... 你的模型输入、推理、输出处理代码 ... g_inferenceCompleted = true; } // 主线程启动推理并维护光标 void StartInferenceWithBusyCursor(HWND hWnd) { // 设置等待光标 SetCursor(LoadCursor(NULL, IDC_WAIT)); // 启动后台线程执行推理 std::thread inferenceThread(RunInferenceThread, yourInputData); inferenceThread.detach(); // 或根据需求使用joinable模式 // 主线程维持消息循环,保证光标更新 MSG msg; while (!g_inferenceCompleted) { if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 短暂休眠降低CPU占用 Sleep(10); } // 推理完成,恢复正常光标 SetCursor(LoadCursor(NULL, IDC_ARROW)); }
*注意:如果你的ORT Session对象不支持多线程共享,务必在后台线程内部创建Session,避免线程安全问题。
2. 推理间隙手动插入消息处理
如果无法拆分线程(比如依赖主线程上下文),可以把大段推理拆分为小批次,每完成一批就处理一次UI消息:
void BatchInferenceWithMessagePump() { SetCursor(LoadCursor(NULL, IDC_WAIT)); for (int batchIdx = 0; batchIdx < totalBatchCount; ++batchIdx) { // 处理单批次ORT推理 ProcessSingleBatch(g_ortSession, batchData[batchIdx]); // 处理UI消息,维持光标旋转 MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } SetCursor(LoadCursor(NULL, IDC_ARROW)); }
*如果推理无法拆分,可尝试结合ORT异步API配合MsgWaitForMultipleObjects,在等待推理完成时处理消息。
3. 使用ORT异步推理API
ONNX Runtime提供RunAsync异步接口,无需阻塞主线程即可执行推理,同时主线程正常处理UI消息:
#include <onnxruntime_cxx_api.h> #define WM_INFERENCE_DONE WM_USER + 1 void AsyncInferenceWithBusyCursor(HWND hWnd) { SetCursor(LoadCursor(NULL, IDC_WAIT)); bool inferenceDone = false; // 准备输入输出张量 Ort::Value inputTensor = ...; std::vector<Ort::Value> outputTensors; // 推理完成回调 auto inferenceCallback = [&](Ort::Status status) { inferenceDone = true; // 跨线程通知主线程恢复光标 PostMessage(hWnd, WM_INFERENCE_DONE, 0, 0); }; // 启动异步推理 g_ortSession->RunAsync(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor, 1, outputNames.data(), outputTensors.data(), 1, inferenceCallback); // 主线程处理消息循环 MSG msg; while (!inferenceDone) { if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) { if (msg.message == WM_INFERENCE_DONE) break; TranslateMessage(&msg); DispatchMessage(&msg); } Sleep(10); } SetCursor(LoadCursor(NULL, IDC_ARROW)); }
*注意:回调函数中禁止直接操作UI,必须通过PostMessage回到主线程处理。
核心原理说明
Windows的等待光标旋转依赖主线程持续处理WM_SETCURSOR等UI消息。ORT同步推理会阻塞主线程消息循环,导致光标停转。所有解决方案的核心都是保证主线程不被推理任务完全占用,维持消息循环的正常运转。
内容的提问来源于stack exchange,提问作者Tullhead
相关产品推荐
相关产品推荐

