【问题标题】:cannot handle QNetworkAccessManager::finised signal in multithreading无法在多线程中处理 QNetworkAccessManager::finised 信号
【发布时间】:2018-02-16 12:33:43
【问题描述】:

我想使用 QNetworkAccessManager 序列化网络请求。为了实现它,我写了这样的课程:

#ifndef CLIENT_H
#define CLIENT_H

#include <queue>
#include <mutex>
#include <condition_variable>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>

class Client : public QObject
{
    Q_OBJECT
    struct RequestRecord
    {
        RequestRecord(QString u, int o):url(u),operation(o){}
        QString url;
        int operation;
    };

    std::mutex mutex;
    std::queue<RequestRecord*> requests;
    QNetworkAccessManager *manager;
    bool running;
    std::condition_variable cv;

public:
    Client():manager(nullptr){}
    ~Client()
    {
        if(manager)
            delete manager;
    }

    void request_cppreference()
    {
        std::unique_lock<std::mutex> lock(mutex);
        requests.push(new RequestRecord("http://en.cppreference.com",0));
        cv.notify_one();
    }

    void request_qt()
    {
        std::unique_lock<std::mutex> lock(mutex);
        requests.push(new RequestRecord("http://doc.qt.io/qt-5/qnetworkaccessmanager.html",1));
        cv.notify_one();
    }

    void process()
    {
        manager = new QNetworkAccessManager;

        connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
        {
            std::unique_lock<std::mutex> lock(mutex);
            RequestRecord *front = requests.front();
            requests.pop();
            delete front;
            reply->deleteLater();
        });

        running = true;

        while (running)
        {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock);

            RequestRecord *front = requests.front();
            manager->get(QNetworkRequest(QUrl(front->url)));
        }
    }
};

#endif // CLIENT_H

可以看出,从网络请求数据和方法进程有两种方法,应该在单独的线程中调用。

我使用这个类如下:

Client *client = new Client;    

std::thread thr([client](){
        client->process();
    });

std::this_thread::sleep_for(std::chrono::seconds(1));

client->request_qt();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
client->request_cppreference();

这个例子说明了从一个线程到网络的 2 个连续请求,并在另一个线程中处理这些请求。一切正常,除了我的 lambda 从未被调用。请求已发送(使用wireshark检查),但我无法得到回复。是什么原因?

【问题讨论】:

  • 它在没有 lambda 插槽的情况下工作?
  • 也许QNetworkAccessManager 需要一个有效的事件循环?
  • @Taz742 不,行为是一样的
  • @thuga 可能是,我会检查它

标签: multithreading qt networking


【解决方案1】:

@thuga 假设问题出在事件循环中。我的线程总是在等待 cv,因此无法处理事件,小技巧解决了这个问题:

void process()
    {
        manager = new QNetworkAccessManager;

        connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
        {
            std::unique_lock<std::mutex> lock(mutex);
            RequestRecord *front = requests.front();
            requests.pop();
            delete front;

            qDebug() << reply->readAll();

            processed = true;
            reply->deleteLater();
        });

        running = true;

        while (running)
        {
            {
                std::unique_lock<std::mutex> lock(mutex);
                cv.wait(lock);

                if(requests.size() > 0 && processed)
                {
                    RequestRecord *front = requests.front();
                    manager->get(QNetworkRequest(QUrl(front->url)));
                    processed = false;
                    QtConcurrent::run([this]()
                    {
                        while (running)
                        {
                            cv.notify_one();
                            msleep(10);
                        }
                    });
                }
            }
            QCoreApplication::processEvents();
        }
    }
};

这不是很明显,因为它使用 3 个线程而不是 2 个线程,但它是带有这个完美短语的 Qt:

QUrl QNetworkReply::url() const 返回内容的 URL 下载或上传。 请注意,网址可能与此不同 的原始请求。 如果 QNetworkRequest::FollowRedirectsAttribute 在请求中设置,然后 此函数返回网络 API 所在的当前 url 访问,即 QNetworkReply::redirected 中发出的 url 信号。

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多