在以下函数中,manager将发出finished(QNetworkReply*)
信号,然后将调用slot函数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);
}
}
如果第一次调用slot函数时发出第二个信号,Qt是否会启动另一个线程来运行slot函数作为对第二个信号的响应?如果是这样,是否有一些方法让第二次调用slot函数等到第一次调用结束?
更新
我的意思是插槽功能有可能同时运行吗?
答案 0 :(得分:5)
除非您明确创建它们,否则Qt程序中没有“可见”的多线程。这意味着,Qt可能会在内部使用线程,例如网络I / O,但多线程是屏蔽你的,你不必关心它。您的代码都不会从其他线程调用,也不会通过需要您关心同步的方式与其他线程共享您的数据。
信号/插槽连接有两种主要形式:直接和排队连接:
直接连接只是同步执行的函数调用,其间有一些额外的函数调用和查找表。如果发出信号,则在“发出信号();”之前立即调用所有插槽。返回(如Laszlo的例子所示)。
另一方面,排队连接也在主线程上执行,没有任何并行/多线程。但是,插槽调用在事件循环的事件队列中入队:首先完成执行发出的方法,控制返回到事件循环,然后在稍后的某个时间点调用插槽( S)。这些插槽是一个接一个地调用的 - 可能没有定义执行的顺序,但它们永远不会被并行调用。
现在QNetworkAccessManager(QNAM)也可以使用事件驱动(*),排队事件:你调用get(),控件返回事件循环; QNAM发送请求;之后,在执行网络I / O后,QNAM会收到响应。将网络I / O和响应完成视为事件,例如鼠标点击:事件发生,它被放入事件队列,稍后事件循环调用QNAM中的一些内部插槽,然后触发fin()发出并调用mySlot()。
(*)实际上,根据平台,QNAM可能确实使用多线程。但这是一个隐藏在用户身上的实现细节 - 所以人们可以坚持使用“事件驱动”的心理模型。
答案 1 :(得分:2)
它不会在第二个线程中启动它。 AFAIK,默认情况下,它将是直接呼叫或排队等待处理。这种情况还取决于您如何管理线程。
您可以选择several connection types,但通常默认(直接或排队)应该没问题。
我将向您展示两个示例,以证明它还取决于究竟发出信号的原因。
#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();
}
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
#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();
}
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