一个线程能否从qt中的另一个线程获取信号?

时间:2018-08-10 00:52:19

标签: multithreading qt signals-slots

我对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在不同的线程中执行?
然后应用程序如何连接不同线程的信号和插槽?
请解释一下为什么会发生这种情况。
谢谢

1 个答案:

答案 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命令,该命令可以顺利运行。 希望这会帮助你。