我对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中,描述
自动连接(默认),如果信号在线程中发出 接收对象具有亲和力,则其行为与 直接连接。否则,行为与“排队”相同 连接。
排队连接当控制返回到接收者线程的事件循环时,将调用该插槽。该插槽在接收者的线程中执行。
尽管APIManager发出信号readyResult(reply);
且此信号已连接到插槽on_readyResult(QNetworkReply*)
,但未调用该插槽。
是因为BackThread和APIManager在不同的线程中执行?
然后应用程序如何连接不同线程的信号和插槽?
请解释一下为什么会发生这种情况。
谢谢
答案 0 :(得分:1)
我在您的代码中发现了问题。
如果将QOjbect移至线程,则它们具有不同的事件循环。
您的dowork()
函数具有无限循环。
因此,这会阻塞backthread
的事件循环。
因此它无法从其他线程获得任何信号。
您不必在QOjbect
的插槽中使用无限循环,它会阻塞事件循环。
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){ //This blocks the event loop. Event Loop couldn't get any signal from the other thread.
QThread::sleep(20);
emit signal_callAPI("http://url.com");
}
}
没有while
命令,该命令可以顺利运行。
希望这会帮助你。