【问题标题】:does the slot function in Qt run on another thread?Qt 中的槽函数是否在另一个线程上运行?
【发布时间】:2014-03-24 23:26:09
【问题描述】:

在下面的函数中,manager 会发出finished(QNetworkReply*) 信号,然后调用槽函数getCategories(QNetworkReply*)

    void getCategories()
    {
        connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getCategories(QNetworkReply*)));

        for(int i = 0; i < stores.size(); ++i)
        {
            request.setUrl(QUrl(QString("http://www.example.com/%1").arg(stores[i].store_id)));

            manager.get(request);
        }
    }

如果在第一次调用槽函数时发出第二个信号,Qt 是否会启动另一个线程来运行槽函数作为对第二个信号的响应?如果是这样,有没有办法让第二次调用槽函数等到第一次调用完成?

更新:

我的意思是槽函数是否有可能同时运行?

【问题讨论】:

    标签: c++ qt qtcore qtnetwork qt-signals


    【解决方案1】:

    除非您明确地创建它们,否则 Qt 程序中没有“可见的”多线程。这意味着,Qt 可能会在内部使用线程,例如网络 I/O,但是多线程对你来说是屏蔽的,你不必关心它。不会从其他线程调用您的任何代码,也不会通过需要您关心同步的方式与其他线程共享您的数据。

    信号/槽连接主要有两种形式:directqueued 连接:

    直接连接只是同步执行的函数调用,中间有一些额外的函数调用和查找表。如果你发出一个信号,所有的槽都会被立即调用,在“发出信号();”之前返回(如 Laszlo 的示例所示)。

    另一方面,队列连接也在主线程上执行,没有任何并行/多线程。但是,槽调用在事件循环的事件队列中排队:首先完成发出的方法,控制返回到事件循环,然后在稍后的某个时间点调用槽( s)。插槽被一个接一个地调用 - 执行顺序可能没有定义,但它们永远不会被并行调用。

    现在 QNetworkAccessManager (QNAM) 也适用于事件驱动 (*),带有排队事件:调用 get(),控制返回事件循环; QNAM 发送请求;稍后,在执行网络 I/O 后,QNAM 收到响应。将网络 I/O 和响应的完成视为事件,例如鼠标点击:事件发生,它被放入事件队列,稍后事件循环调用 QNAM 中的一些内部槽,然后触发finished() 被发射和mySlot() 被调用。

    (*) 事实上,根据平台的不同,QNAM 可能确实使用了多线程。但这是对用户隐藏的实现细节——因此人们可以坚持“事件驱动”的心理模型。

    【讨论】:

      【解决方案2】:

      它不会在第二个线程中启动它。 AFAIK,默认情况下它将是直接呼叫或排队等待处理。具体情况还取决于您管理线程的方式。

      您可以选择several connection types,但通常默认(直接或排队)应该没问题。

      我将向您展示两个示例,以证明它还取决于发出信号的确切内容。

      案例 1(由正在执行的插槽发出)

      main.cpp

      #include <QObject>
      #include <QThread>
      #include <QDebug>
      #include <QCoreApplication>
      
      class MyClass : public QObject
      {
          Q_OBJECT
      
          public:
              explicit MyClass(QObject *parent = 0) : QObject(parent), counter(0)
              {
                  connect(this, SIGNAL(mySignal()),
                          this, SLOT(mySlot()), Qt::QueuedConnection);
              }
      
          signals:
              void mySignal();
          public slots:
              void mySlot()
              {
                  if (counter >= 2) return;
                  ++counter;
                  qDebug() << "mySlot started";
                  emit mySignal();
                  QThread::msleep(1000);
                  qDebug() << "mySlot quit";
              }
      
          private:
              int counter;
      
      };
      
      #include "main.moc"
      
      int main(int argc, char **argv)
      {
          QCoreApplication application(argc, argv);
          MyClass myObject;
          myObject.mySlot();
          return application.exec();
      }
      

      main.pro

      TEMPLATE = app
      TARGET = test
      QT = core
      SOURCES += main.cpp
      

      构建并运行

      moc -o main.moc main.cpp && qmake && make && ./test
      

      输出

      mySlot started 
      mySlot quit 
      mySlot started 
      mySlot quit
      

      在我的示例中,您将在没有排队连接的情况下获得以下输出,表明这将是插槽执行过程中的直接调用:

      mySlot started
      mySlot started
      mySlot quit  
      mySlot quit
      

      案例 2(不是由正在执行的插槽发出)

      main.cpp

      #include <QObject>
      #include <QThread>
      #include <QDebug>
      #include <QCoreApplication>
      #include <QTimer>
      
      class MyClass : public QObject
      {
          Q_OBJECT
      
          public:
              explicit MyClass(QObject *parent = 0) : QObject(parent), counter(0), timer(new QTimer(this))
              {
                  // Note: there is no need for queued connection in this case
                  connect(this, SIGNAL(mySignal()), this, SLOT(mySlot()));
                  connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
                  timer->setSingleShot(true);
                  timer->start(200);
              }
      
          signals:
              void mySignal();
          public slots:
              void mySlot()
              {
                  ++counter;
                  qDebug() << "mySlot started" << counter;
                  QThread::msleep(1000);
                  qDebug() << "mySlot quit" << counter;
              }
      
          private:
              int counter;
              QTimer *timer;
      
      };
      
      #include "main.moc"
      
      int main(int argc, char **argv)
      {
          QCoreApplication application(argc, argv);
          MyClass myObject;
          myObject.mySlot();
          return application.exec();
      }
      

      main.pro

      TEMPLATE = app
      TARGET = test
      QT = core
      SOURCES += main.cpp
      

      构建并运行

      moc -o main.moc main.cpp && qmake && make && ./test
      

      输出

      mySlot started 1 
      mySlot quit 1 
      mySlot started 2 
      mySlot quit 2
      

      【讨论】:

        猜你喜欢
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多