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

Qt线程池使用flaviotordini/http库无法接收消息的问题解决

解决Qt线程池结合flaviotordini/http库无法接收HTTP请求结果的问题

问题场景

在使用Qt线程池(QThreadPool)搭配flaviotordini/http库发起HTTP请求时,出现以下问题:

  • 线程任务(SpiderTask,继承自QRunnable和QObject)的run()函数中,发起HTTP请求后连接HttpReply::finished信号,但槽函数从未执行,无法获取请求结果。

线程池任务代码

SpiderTask::SpiderTask(int id, QString url,QObject *parent)
    : QObject{parent},QRunnable()
{
    this->url = url;
    this->id = id;
    setAutoDelete(true);
}

void SpiderTask::run(){
    QCoreApplication::processEvents();
    int rand = QRandomGenerator::global()->bounded(0,10);
    QThread::sleep(rand);
    auto reply = Http::instance().get("https://www.baidu.com/s?wd=" + this->url);
    connect(reply, &HttpReply::finished, this, [=](auto &reply) {
        if (reply.isSuccessful()) {
            emit recvState(this->id, reply.body());
        } else {
            qDebug() << "Something's wrong here" << reply.statusCode() << reply.reasonPhrase();
        }
        qDebug() << reply.body();
    });
}

主执行代码

QThreadPool::globalInstance()->setMaxThreadCount(ui->threadVloumelineEdit->text().toInt());

int rows = ui->spiderTableView->model()->rowCount();
for(int r = 0; r < rows; r++)
{
    QString url = ui->spiderTableView->model()->index(r,0).data().toString();
    SpiderTask *t = new SpiderTask(r,url);
    connect(t,&SpiderTask::recvState,this,&MainWindow::changeSpiderState);
    QThreadPool::globalInstance()->start(t);
}

问题分析

  1. 对象提前销毁:
    SpiderTask设置了setAutoDelete(true),线程池会在run()函数执行完毕后立即销毁该任务对象。但Http::get()是异步请求,finished信号要等请求完成后才触发,此时SpiderTask已被销毁,信号与槽的连接失效,槽函数无法执行。

  2. 线程无事件循环:
    Qt网络操作依赖事件循环处理异步回调,线程池中的线程默认没有运行事件循环。run()函数执行完毕后线程直接退出,HTTP请求的异步回调无法被处理,导致finished信号无法正常发射。

解决方案

方案一:在run()中启动局部事件循环,等待请求完成

修改SpiderTask的逻辑,关闭自动销毁,启动事件循环等待请求完成后再手动销毁对象:

SpiderTask::SpiderTask(int id, QString url, QObject *parent)
    : QObject{parent}, QRunnable()
{
    this->url = url;
    this->id = id;
    // 关闭自动销毁,手动控制生命周期
    setAutoDelete(false);
}

void SpiderTask::run(){
    int rand = QRandomGenerator::global()->bounded(0,10);
    QThread::sleep(rand);
    
    QEventLoop loop;
    auto reply = Http::instance().get("https://www.baidu.com/s?wd=" + this->url);
    
    connect(reply, &HttpReply::finished, this, [=](auto &reply) {
        if (reply.isSuccessful()) {
            emit recvState(this->id, reply.body());
        } else {
            qDebug() << "请求失败" << reply.statusCode() << reply.reasonPhrase();
        }
        qDebug() << reply.body();
        // 请求处理完毕,退出事件循环
        loop.quit();
    });
    
    // 启动事件循环,等待请求完成
    loop.exec();
    
    // 手动销毁任务对象
    delete this;
}

方案二:改用QObject+moveToThread模式(可选)

如果更倾向Qt的线程对象模型,可将任务逻辑放在QObject派生类中,确保线程有事件循环处理异步回调:

class SpiderWorker : public QObject {
    Q_OBJECT
public slots:
    void doWork(int id, const QString &url) {
        int rand = QRandomGenerator::global()->bounded(0,10);
        QThread::sleep(rand);
        
        auto reply = Http::instance().get("https://www.baidu.com/s?wd=" + url);
        connect(reply, &HttpReply::finished, this, [=](auto &reply) {
            if (reply.isSuccessful()) {
                emit recvState(id, reply.body());
            } else {
                qDebug() << "请求失败" << reply.statusCode() << reply.reasonPhrase();
            }
            emit workDone();
        });
    }
signals:
    void recvState(int id, const QString &body);
    void workDone();
};

// 主函数调用逻辑
QThreadPool::globalInstance()->setMaxThreadCount(ui->threadVloumelineEdit->text().toInt());
int rows = ui->spiderTableView->model()->rowCount();
for(int r = 0; r < rows; r++)
{
    QString url = ui->spiderTableView->model()->index(r,0).data().toString();
    SpiderWorker *worker = new SpiderWorker;
    connect(worker, &SpiderWorker::recvState, this, &MainWindow::changeSpiderState);
    connect(worker, &SpiderWorker::workDone, worker, &SpiderWorker::deleteLater);
    
    // 在线程池线程中执行任务并启动事件循环
    QThreadPool::globalInstance()->start([=](){
        worker->doWork(r, url);
        QEventLoop loop;
        connect(worker, &SpiderWorker::workDone, &loop, &QEventLoop::quit);
        loop.exec();
    });
}

关键注意点

  • 方案一中必须关闭setAutoDelete(true),避免对象在请求完成前被销毁。
  • 无论哪种方案,都要确保线程运行事件循环,否则异步网络回调无法被处理。

内容的提问来源于stack exchange,提问作者Hao Tan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:07:03