【发布时间】:2018-08-10 00:52:18
【问题描述】:
我对 QT 线程没有深入的了解。
我要使用具有后台线程的 QT 应用程序。
后台线程在与主线程不同的另一个线程中执行。
在后台线程中,使用信号槽机制创建新线程来调用api。
例如。
//BackThread.h
{
Q_OBJECT
public:
BackThread(){
thread = new QThread; moveToThread(thread);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(deleteLater()));
}
public slots:
void start(){ thread->start();}
void terminate(){thread->quit(); }
void on_readyResult(QNewtworkReply* reply){ // process response}
void dowork(){
//This is called by signal 'signal_dowork()'
APIManager * manager = new APIManager;
connect(manager, SIGNAL(readyResult(QNetworkReply*)), this, SLOT(on_readyResult(QNeworkReply*)));
connect(this, SIGNAL(signal_callAPI(QString)), manager, SLOT(callAPI(QString)));
connect(manager, SIGNAL(readyResult(QNetworkReply*)), manager, SLOT(terminate())); //Here api call is needed only one time.
manager->start();
while(true){
QThread::sleep(20);
emit signal_callAPI("http://url.com");
}
}
signals:
signal_callAPI(QString);
private:
QThread *thread;
}
//APIManager.h
{
Q_OBJECT
public:
APIManager(){
thread = new QThread; moveToThread(thread);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(deleteLater()));
}
callAPI(QString api){
QNetworkAccessManager *manager;
manager = new QNetworkAccessManager();
// Send web request by this QNewtorkAccessManager ....
//...
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_readyReply(QNetworkReply*)));
}
public slots:
void start(){ thread->start();}
void terminate(){thread->quit(); }
void on_readyReply(QNewtworkReply* reply){
//This is called by the signal 'finished(QNetworkReply*)' of the QNetworkAccessManager, so the readyResult signal is emitted.
emit readyResult(reply); //this signal is emitted,but the connected slot 'on_readyResult' is not fired whenever.
}
signals:
readyResult(QString);
private:
QThread *thread;
}
//MainApp.cpp
BackThread * backthread = new BackThread;
connect(this, SIGNAL(signal_dowork()), backthread, SLOT(dowork()));
backthread->start();
emit signal_dowork(); //This calls dowork() slot.
如您所见,主应用程序启动后台线程并发出信号让后台线程执行某些操作。 (signal_dowork())
这将调用 BackThread 对象的 dowork() 槽。
在这个 BackThread 对象中,这会启动新的线程来调用 api。
BackThread 和 APIManager 线程不同。APIManager class 发送 Web 请求并使用信号槽接收回复。
当接收到QNewtworkAccessManager的finished(QNetworkReply*)信号时,APIManager中的槽on_readyReply(QNetworkReply*)再次发出信号,让BackThread处理这个回复。
但是 BackThread 不会在任何时候收到这个信号。
在QT document中是这样描述的
自动连接(默认)如果信号是在线程中发出的 接收对象具有亲和力,则行为与接收对象相同 直接连接。否则,行为与 Queued 相同 连接。
Queued Connection 当控制返回到接收者线程的事件循环时调用该槽。该槽在接收者的线程中执行。
虽然 APIManager 发出信号 readyResult(reply); 并且此信号连接到插槽 on_readyResult(QNetworkReply*),但不会调用该插槽。
是不是因为BackThread和APIManager是在不同的线程中执行的?
那么应用程序如何连接不同线程的信号和槽呢?
请解释一下为什么会发生这种情况。
谢谢
【问题讨论】:
-
在
connect(manager, SIGNAL(readyResult(QNetworkReply*)), manager, SLOT(terminate()));manager 的 terminate() 槽被调用? -
是的,所以
manager内存被释放了。我已经调试过了。 -
connect(manager, SIGNAL(readyResult(QNetworkReply*)), this, SLOT(on_readyResult(QNeworkReply*)));connect(manager, SIGNAL(readyResult(QNetworkReply*)), manager, SLOT(terminate()));manager收到readyResult然后触发terminate&on_readyResult。所以先摧毁自己,然后失去连接。 -
@Jiu,信号
readyResult是经理之一。 -
尝试删除
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), this, SLOT(deleteLater()));中的APIManager看看会发生什么。
标签: multithreading qt signals-slots