将信号连接到Lambda时Qt :: QueuedConnection和Qt :: DirectConnection之间的区别

问题描述

让我们考虑两个QObjectssenderObject类型的SenderObjectreceiverObject类型的ReceiverObject的情况。 senderObject是在辅助线程上创建的,而receiverObject是在主线程上创建的。现在,假设SenderObject一个信号somethingsChanged,并考虑以下代码片段:

代码段1:

int main(int argc,char *argv[]) {
  QCoreApplication a(argc,argv);
  QThread t;
  SenderObject senderObject = new SenderObject();
  senderObject.movetoThread(&t);
  ReceiverObject receiverObject = new ReceiverObject();
  //in this case we kNow for a fact that receiverObject's 
  //onSomethingsChanged() will be called on the main thread
  QObject::connect(senderObject,&SenderObject::somethingsChanged,receiverObject,&ReceiverObject::onSomethingsChanged,Qt::QueuedConnection);
  t.start();
  return a.exec();
}

现在让我们考虑以下代码片段:

代码段2:

int main(int argc,argv);
  QThread t;
  SenderObject senderObject = new SenderObject();
  senderObject.movetoThread(&t);
  //where will qDebug() << "Hello,world" be executed? 
  //On the main thread again since the lambda lives on the main thread?
  QObject::connect(senderObject,[]{qDebug << "Hello,world";});
  t.start();
  return a.exec();
}

Slampet2中的lambda是否也会在主线程上执行,因为lambda已经在主线程上声明了,还是会在与senderObject相同的线程中执行?

解决方法

这是我们的课程SenderObject:

class Sender : public QObject {
  Q_OBJECT
 public:
  explicit Sender() : QObject() {
    _timer.setInterval(1000);
    connect(&_timer,&QTimer::timeout,this,[this] { emit somethingsChanged(); });
    _timer.start();
  }

 signals:
  void somethingsChanged();

 private:
  QTimer _timer;
};

由于没有QObject::connect的重载将使用lambda和Qt连接类型参数,因此Snippet2将在发送方的线程(即工作线程)中执行。

为了强制lambda在主线程上执行,这是一种解决方法:

int main(int argc,char *argv[]) {
  QCoreApplication a(argc,argv);
  QThread t;
  SenderObject senderObject = new SenderObject();
  senderObject.moveToThread(&t);
  QObject::connect(senderObject,&SenderObject::somethingsChanged,new QObject,[]{qDebug << "Hello,world";},Qt::QueuedConnection);
  t.start();
  return a.exec();
}

由于在主线程上调用了new QObject,因此lambda也将在主线程上执行。

或者,如果我们不希望看到new,这将起作用:

int main(int argc,argv);
  QThread t;
  SenderObject senderObject = new SenderObject();
  senderObject.moveToThread(&t);
  QObject object;
  QObject::connect(senderObject,&object,Qt::QueuedConnection);
  t.start();
  return a.exec();
}

或者,甚至更好的解决方案是使用qApp,它是应用程序的一个实例,是一个单例,可以在任何地方使用。

int main(int argc,qApp,Qt::QueuedConnection);
  t.start();
  return a.exec();
}