在多个线程中使用QNetworkAccessManager
最近发现Tangram发出了URL request, 但是却收不到URL reponse
经研究后发现这是一个线程问题: Tangram会在多个线程发送URL request, 但是在实现时, 却没有考虑线程问题, 程序在运行时得到如下warning:
QObject: Cannot create children for a parent that is in a different thread. (Parent is QNetworkAccessManager(0x21dcba0), parent's thread is QThread(0x20be1c0), current thread is QThread(0x7f48e0044730)
在移植Tangram到Qt平台时, 网络请求使用的是QNetworkAccessManager, QNetworkAccessManager的使用很简单:
QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
这里碰到的问题是:Tangram可能在多个线程发送URL, 但是QNetworkAccessManager只能在生成它所在的线程中工作, 解决办法是使用Qt的SIGNAL/SLOT机制, 把该URL request post到正确的线程中:
class URLTaskWorker{ public: URLTaskWorker(){ connect(this,SIGNAL(startRequest()),this, SLOT(onRequest()), Qt::QueuedConnection); } public: void handleTask(QUrl url){ this->url = url; emit StartNewRequest(); } signals: void startRequest(); private slots: void onRequest(){ qnam.get(url); } private: QNetworkAccessManager qnam; QUrl url; };
这里要注意的是, 在connect startRequest和onRequest时, 要使用Qt::QueuedConnection, 使用默认的Qt::AutoConnection不工作, 参考Qt帮助文档:
Qt::QueuedConnection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
这也是一个Qt的线程安全的在不同线程间传递消息的方法。