【问题标题】:Could one thread get the signal from the other one in the qt?一个线程可以从 qt 中的另一个线程获取信号吗?
【发布时间】: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


【解决方案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 命令,运行顺利。 希望这会帮助你。

【讨论】:

  • 那应用怎么会有死循环呢?
  • 这是你的选择,我想你会喜欢的。 connect(this,SIGNAL(restart()),this,SLOT(dowork()),Qt::QueuedConnection)。如果你使用 Qt::AutoConnection,它会阻塞当前函数。所以它会无限调用dowork()。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
  • 1970-01-01
相关资源
最近更新 更多