does the slot function in Qt run on another thread? - c++

In the following function, manager will emit finished(QNetworkReply*) signal, then the slot function getCategories(QNetworkReply*) will be called.
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);
}
}
If the second signal emitted when the first call of the slot function, does Qt start another thread to run the slot function as the response to the second signal? And if it is so, is there some method to let the second call of slot function wait until the first call is finished?
UPDATE:
I mean is there a possibility that the slot function run in the same time?

Unless you create them explicitly, there's no "visible" multi-threading in a Qt program. That means, Qt might use threads internally for e.g. network I/O, but that multithreading is shielded from you and you don't have to care about it. None of your code will be called from other threads, nor will your data be shared with other threads by means that would require you to care about synchronization.
Signal/slot connections come it two main flavors: direct and queued connections:
Direct connections are just function calls that are executed synchronously, with some extra function calls and lookup tables in between. If you emit a signal, all slots are called immediately, before the "emit signal();" returns (as Laszlo's example demonstrates).
Queued connections on the other hand are also executed on the main thread, without any parallelism/multi-threading. However, the slot calls are enqueued in the event loop's event queue: The method doing the emit is completed first, the control returns to the event loop, which then at some later point in time calls the slot(s). The slots are called one after another - the order of execution might not be defined, but they will never be called in parallel.
Now QNetworkAccessManager (QNAM) also works event-driven (*), with queued events: You call get(), the control returns to the event loop; the QNAM sends the request; later, after performing the network I/O, the response is received by QNAM. Think of the network I/O and completion of the response as events, like e.g. mouse clicks: The event occurs, it is put into the event queue, later the event loop calls some internal slot in QNAM, which then triggers finished() to be emitted and mySlot() to be called.
(*) In fact, depending on the platform, QNAM might indeed use multithreading. But that's an implementation detail hidden from the user - so one can stick to the "event-driven" mental model.

It does not start it in a second thread. AFAIK, it will be either a direct call or queued for handling by default. The situation also depends on how you are managing your threads.
There are several connection types you can choose from, but usually, the default (direct or queued) should be fine.
I will show you two examples to demonstrate that it also depends on what exactly emits the signal.
Case 1 (Emitted by the slot being executed)
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
Build and Run
moc -o main.moc main.cpp && qmake && make && ./test
Output
mySlot started
mySlot quit
mySlot started
mySlot quit
You would get the following output without queued connection to indicate that it would be a direct call in the middle of the slot execution in my example:
mySlot started
mySlot started
mySlot quit
mySlot quit
Case 2 (not emitted by the slot being executed)
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
Build and Run
moc -o main.moc main.cpp && qmake && make && ./test
Output
mySlot started 1
mySlot quit 1
mySlot started 2
mySlot quit 2

Related

Using Controller and QT Worker in a working GUI example

I created a minimal QT GUI example to update widgets from a worker thread based on the recommended approach in the The QThread 5.12 documentation.
As described in the QThread 5.12 documentation, the Worker class (with a potentially long void doWork(const QString &parameter) method is:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString &parameter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
and the corresponding Controller class is:
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
Unlike sub-classing from a QThread, the approach shown in the documentation shows the recommended way that uses a controller and a worker that extends QObject rather than extending QThread and overriding the QThread::run method, however it does not show how these should be used in the context of a real example.
I need to use an QT Worker thread that updates widgets on a GUI using a timer.
I also need to be able to halt and restart/relaunch this thread with different parameters and I am having some trouble with how to do this correctly. indicates the preferred way to do this via a Controller and a Worker but the connect logic is a bit confusing.
The place where I need help is how to properly integrate the timer in my worker thread and also how to stop and restart a replacement worker when the current one has either finished or been interrupted and restarted.
My working code is made up of the following files.
Controller.h
#pragma once
// SYSTEM INCLUDES
#include <QObject>
#include <QThread>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller(/*MainWindow* mainWindow*/) {
auto worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &) {
// how do I update the mainWindow from here
}
signals:
void operate(int);
};
Worker.h
#pragma once
// SYSTEM INCLUDES
#include <QTimer>
#include <QObject>
#include <QEventLoop>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(int count) {
QString result = "finished";
// Event loop allocated in workerThread
// (non-main) thread affinity (as moveToThread)
// this is important as otherwise it would occur
// on the main thread.
QEventLoop loop;
for (auto i=0; i< count; i++) {
// wait 1000 ms doing nothing...
QTimer::singleShot(1000, &loop, SLOT(quit()));
// process any signals emitted above
loop.exec();
emit progressUpdate(i);
}
emit resultReady(result);
}
signals:
void progressUpdate(int secondsLeft);
void resultReady(const QString &result);
};
MainWindow.h - I needed to add a Controller member here. I also added an updateValue slot here where I wish to update the GUI. Unfortunately I don't know how to get the controller or the worker to connect a signal from the thread to update this slot.
#pragma once
// SYSTEM INCLUDES
#include <memory>
#include <QMainWindow>
// APPLICATION INCLUDES
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
namespace Ui {
class MainWindow;
}
class Controller;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void updateValue(int secsLeft);
private:
Ui::MainWindow *ui;
std::unique_ptr<Controller> mpController;
};
MainWindow.cpp -
#include <QThread>
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "Controller.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mpController(std::make_unique<Controller>())
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
emit mpController->operate(100);
}
void MainWindow::updateValue(int secsLeft)
{
ui->secondsLeft->setText(QString::number(secsLeft));
}
and finally main.cpp
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I basically need help and an explanation on how I should use the QT Thread's controller/worker integrated in my GUI.
I'll try to answer all the issues you're addressing in your question:
I don't know how to get the controller or the worker to connect a signal from the thread to update this slot.
You got that almost right yourself.
Your Worker lives within the event loop of your Controller:
+--GUI-thread--+ (main event loop)
| MainWindow, |
| Controller --o-----> +--QThread--+ (own event loop in ::exec())
+--------------+ | Worker |
+-----------+
Communication between Controller and Worker must happen through signal-slot-connections. In between MainWindow and Controller signals help keep dependencies to a minimum.
You can imagine Controller as a kind of relay: Commands from MainWindow get forwarded through Controller to the Worker. Results from Worker get forwarded through the Controller to anyone who is interested.
For this, you can simply define signals in Controller:
class Controller : public QObject
{
//...
signals:
void SignalForwardResult(int result);
};
and then instead of
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
use the new signal:
connect(worker, &Worker::resultReady, this, &Controller::SignalForwardResult);
// Yes, you can connect a signal to another signal the same way you would connect to a slot.
and in your MainWindow constructor:
//...
ui->setupUi(this);
connect(mpController, &Controller::SignalForwardResult, this, &MainWindow::displayResult);
Likewise for Worker::progressUpdate() -> Controller::SignalForwardProgress() -> MainWindow::updateValue().
how to stop and restart a replacement worker when the current one has either finished or been interrupted and restarted.
Either create a new worker for each task or use a persistent worker that can react on new task requests.
You start a task by sending it to the worker ::doWork() function.
A task ends by itself when the long work is finished. You get a notification via the worker's resultReady signal.
Cancelling a task is only possible by intervention
If you indeed have a QTimer, you can use a cancel() slot because that will be invoked in the thread's event loop before the next timeout.
If you have a long-running calculation, you need to share some token that you read from inside your calculation method and set from your GUI thread. I usually use a shared QAtomicInt pointer for that, but a shared bool usually suffices too.
Note that while a method is running on a thread, that thread's event loop is blocked and won't receive any signals until the method is finished.
DON'T use QCoreApplication::processEvents() except if you really know, what you're doing. (And expect that you don't!)
how to properly integrate the timer in my worker thread
You shouldn't.
I guess you use a background thread because there is so much work to do or you need to blocking wait for so long that it would block the GUI, right? (If not, consider not using threads, saves you a lot of headaches.)
If you need a timer, make it a member of Worker and set its parentObject to the Worker instance. This way, both will always have the same thread affinity. Then, connect it to a slot, like Worker::timeoutSlot(). There you can emit your finish signal.

what leads to the different outcome of the synchronously block function `sleep` in GUI and non GUI program

I use synchronously block QThread::sleep() function to do timing, which shows number one after another by the time.
the expected running process is synchronously block current thread 2 seconds, and run the following code to change displayed number, and synchronously block another 2 seconds, and so on..., the thought works well in non GUI program.
but in GUI mode, the label only show 9, which is the last number to be displayed.
what leads to the different outcome of the synchronous blocking function sleep in GUI and non GUI program?
#include <windows.h>
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QThread>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
//slot of start timing button
void Widget::on_pushButton_2_clicked()
{
for(int i=0;i<10;i++){
QThread.sleep(2);
ui->label->setText(QString::number(i));
}
}
The GUI needs to continually verify events such as the mouse, the keyboard, etc. and perform actions if certain conditions are met, that is called eventloop. In the case of sleep() it is a blocking task that does not allow the eventloop to run, generating the GUI to freeze (if you want to verify it, try to change the size of the window), so inside the GUI thread you should avoid to use that kind of functions, the blocking tasks you have to turn them into asynchronous or execute it in another thread.
But the task of the sleep() can be replaced by a QTimer without blocking the GUI:
*.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QTimer>
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_2_clicked();
void onTimeout();
private:
Ui::Widget *ui;
int counter;
QTimer timer;
};
#endif // WIDGET_H
*.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
counter = 0;
connect(&timer, &QTimer::timeout, this, &Widget::onTimeout);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_2_clicked()
{
timer.start(2000);
}
void Widget::onTimeout()
{
ui->label->setText(QString::number(counter));
counter++;
if(counter > 10){
counter = 0;
timer.stop();
}
}
Another option is to use QEventLoop with QTimer:
void Widget::on_pushButton_2_clicked()
{
for(int i=0;i<10;i++){
QEventLoop loop;
QTimer::singleShot(2000, &loop, &QEventLoop::quit);
loop.exec();
ui->label->setText(QString::number(i));
}
}
Update:
what leads to the different outcome of the synchronous blocking function sleep in GUI and non GUI program?
If you are creating a non GUI application using Qt you will also have problems, although the effect may be less visible.
In the case of the GUI as I said there is an eventloop that handles events, and among them that of repainting, I mean when you set the new text in the QLabel, this is not painted automatically but Qt decides the right moment. That's why when you use QThread::sleep() you do not have time to update the painting.
Obviously in a non GUI application, the eventloop does not verify many events as the one painted by it does not see the effect, in fact in a script that only prints numbers it does not verify any event.
To notice the problem, let's use the following example:
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [](){
qDebug()<< "hello world";
});
timer.start(1000);
qDebug()<< "start blocking";
QThread::sleep(10);
qDebug()<< "end blocking";
return a.exec();
}
We will see that nothing is printed until the sleep() ends, that is, blocking the eventloop that allows the QTimer to do its work.
Answering your comment:
but what still makes me puzzled is why after finishing executing sleep function, after stopping blocking current thread, the following codes can't run as normal
ui->label->setText(QString::number(i)); this statement, right after sleep function
Asynchronous tasks such as painting have less priority than synchronous tasks, that is to say first Qt will execute the for loop and then just do the asynchronous tasks, so in the for the variable that stores the QLabel text is updated, that is to say 0, 1 , ..., 9, and after that, the task is handed over to the eventloop so that it just paints the last value, that is, the 9.
Note:
You can force the evenloop to update within synchronous execution with QXXXApplication::processEvents(), but this is often considered a bad practice, I only show it so you know it but avoid using it:
for(int i=0;i<10;i++){
QThread.sleep(2);
ui->label->setText(QString::number(i));
QApplication::processEvents();
}

How to find out from the slot which signal has called this slot?

I mean if I have many different signals which are connected to the same slot. I saw this question but can't understand the link in the answer. Can you give me simple example?
I think you can use this method:
[protected] int QObject::​senderSignalIndex() const
From Qt documentation:
Returns the meta-method index of the signal that called the currently executing slot, which is a member of the class returned by sender(). If called outside of a slot activated by a signal, -1 is returned.
For signals with default parameters, this function will always return the index with all parameters, regardless of which was used with connect(). For example, the signal destroyed(QObject *obj = 0) will have two different indexes (with and without the parameter), but this function will always return the index with a parameter. This does not apply when overloading signals with different parameters.
Warning: This function violates the object-oriented principle of modularity. However, getting access to the signal index might be useful when many signals are connected to a single slot.
Warning: The return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
This function was introduced in Qt 4.8.
Here is a small example that I created for you that demonstrates how it works:
#include <QTimer>
#include <QMetaObject>
#include <QMetaMethod>
#include <QCoreApplication>
#include <QDebug>
#include <QObject>
class Foo : public QObject
{
Q_OBJECT
public slots:
void mySlot() {
QMetaMethod metaMethod = sender()->metaObject()->method(senderSignalIndex());
qDebug() << metaMethod.name();
qDebug() << metaMethod.methodSignature();
qApp->quit();
}
};
#include "main.moc"
int main(int argc, char **argv)
{
QCoreApplication coreApplication(argc, argv);
QTimer timer;
Foo foo;
QObject::connect(&timer, &QTimer::timeout, &foo, &Foo::mySlot);
timer.setSingleShot(true);
timer.start(1000);
return coreApplication.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"timeout"
"timeout()"

Substitute for sleep function in Qt/C++

So I am writing a program that displays each letter of a word for 1 second with a 1 second interval between the letters. (It's for a spelling exercise for grade 1). I am currently using the sleep function to "pause" the program for 1 second before it "updates" again. After that it displays the word for a second and then removes it. I repaint before the sleep function, else it does not seem to update in time.
Here is the basic function:
QString word = "apple";
QThread thread;
for(int i = 0; i < word.size(); i++)
{
ui->label1->setText(word[i]);
ui->label1->repaint();
thread.sleep(1);
ui->label1->setText("");
thread.sleep(1);
}
ui->label1->setText(word);
ui->label1->repaint();
thread.sleep(1);
ui->label1->setText("");
This works fine, except the program stops responding (even though I can see the correct output is still displaying) until the whole function is done executing then it works fine again. Is there another way I can accomplish this goal without using sleep? I am quite new to Qt.
Update I made. I made a new class that will handle the timer, but it does not seem to actually connect the signal and slot. Here is the .h file:
#ifndef TIMERDISPLAY_H
#define TIMERDISPLAY_H
#include <QTimer>
#include <QObject>
class TimerDisplay:public QObject
{
Q_OBJECT
public:
TimerDisplay();
public slots:
void expired();
private:
QTimer timer;
};
#endif // TIMERDISPLAY_H
and the .cpp file:
#include "timerdisplay.h"
#include <QDebug>
TimerDisplay::TimerDisplay()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(expired()));
timer.setSingleShot(false);
timer.setInterval(1000);
timer.start();
}
void TimerDisplay::expired()
{
qDebug()<<"timer expired";
}
Use QTimer or QElapsedTimer if you need more precision.
main.cpp
#include <QTimer>
#include <QCoreApplication>
#include <QString>
#include <QTextStream>
#include <QDebug>
int main(int argc, char **argv)
{
QCoreApplication application(argc, argv);
QTimer timer;
QTextStream textStream(stdout);
QString word = "apple";
int i = 0;
QObject::connect(&timer, &QTimer::timeout, [&textStream, word, &i] () {
if (i < word.size()) {
textStream << word.at(i) << flush;
++i;
}
});
timer.start(1000);
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
apple
This is happening, because you're blocking the thread. In most cases you're interested in using event loop.
You can use timer and increment a counter in a slot function. Every QObject has support for timer. You can start it using int QObject::startTimer(int interval) and it will call virtual void timerEvent(QTimerEvent *event) every interval miliseconds (it's a virtual method - reimplement it).
You can also use QTimer and connect QTimer::timeout() signal to accomplish the same thing.
Inside timer handler increment a counter and print the character.
It's a good idea to put your hands on finite state machine concept. FSMs are a great tool for solving similar problems problems. In fact, using a timer callback you create a state machine, but very simple one.
I still don't know what the problem is, but I found a make-shift solution. In my program I include one class (eg class1) into my mainwindow.cpp and from that class I include the timer class. I solved the problem by removing the timer class and adding all those functions to class1. Doesn't make sense to me, but it works.

Has-a relationships and signals in Qt

I'm new to development with Qt and our design uses the has-a relationship in a couple of places. In some of these cases the container should expose the signal of the internal object, and then I've currently written a private slot for each such signal, where I in practice re-emit the signal again. Is there some short-cut available in Qt that aids in exposing the signal of the internal object on the container?
You don't have to create a slot for reemiting the signal, you could connect a signal with another signal. This way you will avoid the slot definition.
So in your container you would have something like this:
connect(object, SIGNAL(signal1()), this, SIGNAL(signal1()));
Of course you have to redefine the signal on your container.
For more details check the signal slot documentation
From the documentation:
You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)
The following is legal:
connect(sender, SIGNAL(originalSignal()), SIGNAL(newSignal()));
The re-emitting of Signals also allows re-emitting multiple signals.
testclass.h:
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
explicit TestClass(QObject *parent = 0)
{
connect(this, SIGNAL(signal1()), this, SIGNAL(signal2()));
connect(this, SIGNAL(signal1()), this, SIGNAL(signal2()));
connect(this, SIGNAL(signal2()), this, SLOT(slot()));
}
void emitSignal1()
{
emit signal1();
}
signals:
void signal1();
void signal2();
public slots:
void slot()
{
qDebug() << "SLOT HAS BEEN CALLED";
}
};
main.cpp:
#include <QCoreApplication>
#include "testclass.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestClass instance;
instance.emitSignal1();
return a.exec();
}
The result is that the slot is called twice in this case.
If it is internal structure of your class, why won't you make it friend class. Then you can inside your internal structure call directly emit parentObj->signal()