You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:30:45