The code is in C++/Qt.
Basically, I wanted to create a timer (but not started) and started it later when necessary. But it did not work.
If I created and started the timer immediately, it worked as expected.
The idea of the code is like the followings:
mytimer.cpp:
#include "mytimer.h"
#include <QtCore>
MyTimer::MyTimer()
{
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(mySlot()));
// timer->start(1000);
}
void MyTimer::mySlot()
{
qDebug()<<"timer executed";
}
MyTimer::startTimer(void)
{
timer->start(1000);
}
Note: startTimer() is triggered from another thread with an signal. I did debug the code and startTimer() function did get called as expected but the Timer did NOT start.
And in the main.cpp:
#include <QApplication>
#include "mytimer.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyTimer mtimer;
qDebug()<<"DONE";
return a.exec();
}
I don't know why I could not start the timer later.
This is the main problem: "Note: startTimer() is triggered from another thread with an signal". However, you instantiate your MyTimer on the main thread which is different, since you try to start your timer on a different thread. You should either create your timer on the thread you want timeout to trigger or move your timer to that thread, and then connect your timer to timeout and slot. For instance, you could do like this maybe (not checked if it would really work):
MyTimer::startTimer(void)
{
timer->moveToThread(QThread::currentThread());
connect(timer, &QTimer::timeout, this, &MyTimer::mySlot);
timer->start(1000);
}
However, I would suggest the following approach, since moving objects between threads might mess up with your code, make it harder to manage, so the simpliest possible solution should be prefered to solve your problem, in my opinion.
MyTimer::startTimer(void)
{
// Create your timer on the thread you want
timer = new QTimer(this);
// Connect signal and slot
connect(timer, &QTimer::timeout, this, &MyTimer::mySlot);
// Start the timer
timer->start(1000);
}
Which one to use is up to you, but you should know that connecting signals and slots between different threads is not working under Qt, and all of the connections should be instantiated on the same thread, and actions triggering these connections should also be executed on the same thread where connection has been introduced.
Related
I'm trying to understand what is and isn't allowed when it comes to QWidget and Qt concurrency. I've created a Widget which has a slow_function and I'm considering three cases:
Run the slow_function on the GUI thread. This results in the expected behaviour; the GUI becomes unresponsive while waiting for the function to return.
Use QtConcurrent::run(this, &Widget::slow_function). I was surprised to see that this didn't block the GUI. I've confirmed that the thread affinity of my instance is still the GUI thread, nevertheless, the function seems to be executing on a separate thread. Is such an approach allowed and is this the expected behaviour (documentation link would be really helpful)? Is such an approach safe if I can guarantee that slow_function is thread-safe?
Create a subclass of QThread which holds a pointer to my widget. Override the run method to call slow_function. The behaviour is the same as Case 2. This is also surprising as the thread affinity is still the GUI thread (besides, we are not even allowed to use moveToThread on a QWidget). Why is this running on a separate thread? Is moveToThread meant to be useful only when we are interested in calling slots via signals sent from another thread?
Thank you for reading. Here is the relevant code starting with my the header file:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QDebug>
#include <QPushButton>
#include <QLayout>
#include <windows.h>
#include <QtConcurrent/QtConcurrent>
#include <QThread>
#include <QApplication>
class Widget;
class Thread: public QThread
{
public:
Thread(Widget* widget)
: m_widget(widget){}
protected:
void run() override;
private:
Widget* m_widget;
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = nullptr)
: QWidget(parent)
, m_thread(this){
auto layout = new QVBoxLayout(this);
auto button = new QPushButton("Case 1: Run on gui thread");
auto button2 = new QPushButton("Case 2: Run with qtconcurrent");
auto button3 = new QPushButton("Case 3: Run with qthread");
connect(button, &QPushButton::clicked, this, &Widget::slow_function);
connect(button2, &QPushButton::clicked, this, &Widget::use_concurrent);
connect(button3, &QPushButton::clicked, this, &Widget::use_qthread);
layout->addWidget(button);
layout->addWidget(button2);
layout->addWidget(button3);
}
~Widget()
{
m_thread.quit();
m_thread.wait();
}
public slots:
void slow_function()
{
qDebug() << "Starting";
auto gui_thread = QApplication::instance()->thread();
auto this_thread = thread();
qDebug() << "Thread affinity is" << (gui_thread == this_thread ? "gui_thread" : "non_gui_thread");
Sleep(5000);
qDebug() << "Finished";
}
void use_concurrent()
{
QtConcurrent::run(this, &Widget::slow_function);
}
void use_qthread()
{
m_thread.start();
}
private:
Thread m_thread;
};
#endif // WIDGET_H
and the main.cpp file:
#include "widget.h"
#include <QApplication>
void Thread::run()
{
m_widget->slow_function();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
You should not do any UI things in nonmain threads. The UI means
widget interaction
model
Run the slow_function on the GUI thread
That's not allowed, nothing should block the GUI thread.
Is such an approach safe if I can guarantee that slow_function is thread-safe?
It's okay to run slow function in a different thread. But...
what happens when the user closes the application, but the function still executes?
I have done this, but I prefer to encapsulate it in a separate class.
Create a subclass of QThread which holds a pointer to my widget.
You should only subclass QThread if the subclass is a thread. Like, subclassing an animal class will give you an animal, not a chair with four legs.
Is moveToThread meant to be useful only when we are interested in calling slots via signals sent from another thread?
moveToThread changes the affinity of the object. So, slots are always executed in the correct thread, when you call invokeMethod, the method is executed in the correct thread. When an event is delivered, the event handler is always called in the appropriate thread.
The whole purpose of QtConcurrent::run() is to make running heavy workloads in a thread easier. If your use-case allows for it, great!
Pair it with a QFutureWatcher to retrieve the result after your slow_function is finished.
Using QThread is another option, but it makes more sense when you have a long-lived object. Instead of subclassing, I find it easier to use the worker model: create a worker class with signals/slots, call moveToThread on it with a vanilla QThread object, connect/subscribe, start the thread
QWidget is a way to create GUI functionality in Qt. While it may be possible to use such objects in non-gui threads, it's best you separate your compute workloads from GUI (don't put your slow_function into widget classes).
I'm trying to execute a network request and wait for the response before moving on. Whereas using a QEventLoop works to wait for the request, the problem is if there are other signals fired in other parts of the program they will execute first.
Here is an example of the code re-producing the problem. You can see the network request (I'm using http://example.com here just for example) is clearly going to be issued before the second singleShot timer will fire.
#include <QApplication>
#include <QTimer>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
void longFunction()
{
qDebug() << "Starting Long Function";
QEventLoop localEventLoop;
QNetworkAccessManager manager;
QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://example.com")));
QObject::connect(reply, &QNetworkReply::finished, &localEventLoop, &QEventLoop::quit);
// I wish to block here
// - do not want to pass this point and run
// other events if fired from the main event loop
localEventLoop.exec();
qDebug() << "Finishing Long Function";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTimer::singleShot(0, &longFunction);
QTimer::singleShot(1, []() {
qDebug() << " -- Some other function that was issued after";
qDebug() << " -- 'longFunction' started but before 'longFunction' ended";
});
return a.exec();
}
Here is the output:
Here is the desired output:
Edit
To add some more info. The code above is obviously an over simplification of the problem as I can't easily post all of the code. Basically whats happening is there is code somewhere else in my project that will emit a signal that is connected to the longFunction() above. Obviously I want to wait for a response from the REST call before continuing because the response will dictate the elements later in that function. The issue is that at some point later (potentially before the REST call finishes), some other parts of my code might trigger some other signal and I don't want those other signals to be processed. I just want to wait for the ONE connection on the localEventLoop to be processed.
Any help would be greatly appreciated
QTimer::singleShot(0, &longFunction);
is an asynchronous function. It returns before void longFunction() executed the QEventLoop. The result is that your second QTimer::singleShot(1, []() { will trigger immediately. The solution is to move QEventLoop outside your function, before QTimer::singleShot(1, []() {
In the documentation of QTimer there is a Properties-section, containing the active-property.
This made me believe, there might be something like a activeChanged-signal, I could connect to.
For IMHO unapparent reasons
QObject::connect(m_timer, &QTimer::activeChanged, this, &MyObject::mySlot);
failes, stating activeChanged is no member of QTimer.
Basically, I want to do something, when the timer gets initially started (so not on restart) or finally stopped. When the signal activeChanged does not exist, has anyone knowledge:
Why it is a property at all?
If there are some other signals to connect to, to do this?
Any way to hook in, and do something when the timer is started or stopped?
test in main.cpp
QTimer* tim = new QTimer;
QObject::connect(tim, &QTimer::activeChanged, qApp, [tim](){qDebug() << "Active changed" << tim->isActive(); });
tim->start(40000); // I want to get a signal
tim->start(100); // I don't want to get a signal
tim->stop(); // I want to get a signal
Create your own timer class and encapsulate QTimer:
class Timer : public QObject
{
Q_OBJECT
QTimer m_timer;
public:
Timer ()
{
connect(&m_timer, &QTimer::timeout, this, &Timer::timeout);
}
void start(int msec)
{
if (m_timer.isActive())
{
// Restart detected -> block signal
m_timer.blockSignals(true);
m_timer.start(msec);
m_timer.blockSignals(false);
}
else
{
m_timer.start(msec);
}
}
}
Since the class Timer has the full control and knowledge of the QTimer, you can have any apparent behavior you want.
I would like to measure which events in my application take long time to execute in main thread (blocking GUI) or at least if there are any that take more than, lets say, 10msec. I obviously use threading and concurrency for tasks that take a long time, but it's sometimes hard to draw the line between what to put in other threads and what can stay with GUI. Especially with app that runs on multiple OSes and both new and few-years old hardware.
I looked at QApplication (and QCoreApplication) but it doesn't have any "processSingleEvent" kind of function which I cloud easily override and wrap with time measurement. Event filters also doesn't do the trick because AFAIU there is no way to get a notification after event is processed.
I thought that I could call QApplication::processEvents manually (without ever invoking exec), but again it doesn't give single-event granularity and, as I read, it doesn't handle destroy events.
I looked at QCoreApplication::exec implementation, and saw that it uses QEventLoop internally, so if I wanted to add my special code to original implementation I would have to reimplement both QApplication and QEventLoop copying a lot of code from Qt source...
Edit: the question obviously is: How to measure event handling time in possibly simple and "clean" way?
Override bool QCoreApplication::notify ( QObject * receiver, QEvent * event ):
class MyApplication : public QApplication
{
QElapsedTimer t;
public:
MyApplication(int& argc, char ** argv) : QApplication(argc, argv) { }
virtual ~MyApplication() { }
virtual bool notify(QObject* receiver, QEvent* event)
{
t.start();
bool ret = QApplication::notify(receiver, event);
if(t.elapsed() > 10)
qDebug("processing event type %d for object %s took %dms",
(int)event->type(), receiver->objectName().toLocal8Bit().data(),
(int)t.elapsed());
return ret;
}
};
int main(int argc, char *argv[])
{
MyApplication a(argc, argv);
...
That also happens to be the place for a catch all type exception handling.
Qt documentation states that it is possible to connect two signals together:
It is even possible to connect a signal directly to another signal.
I tried:
connect(x, SIGNAL(S()), y, SIGNAL(func()));
and it works as mentioned, but Qt documentation continues:
(This will emit the second signal immediately whenever the first is emitted.)
Does this mean that QueuedConnection will not work correctly? Can I connect two signals across threads?
The reason I am asking this is because I solved a class of crashes on an application by avoiding this, but I am not sure if this was related to connecting signals together.
It shouldn't be a great deal different from a signal/slot connection. Let's take a look at underlying mechanism of signals/slots. There is an event queue in each thread which maintains signals (events) that have been emitted but not processed yet. So whenever the execution returns to the event loop the queue is processed. Event loop itself doesn't handle the events. Rather it delivers them to the objects so they can handle it. In this special case, I suppose that the object would emit another signal which would be inserted in the queue. When the execution returns to event loop the new signal is handled by the object again. Here is a test which proves the above argument.
If you run the codes attached, the output would be:
before signal()
after signal()
slot() called
which means defining a signal-signal connection type as queued between threads have the expected queued behaviour, that rejects the argument which it is always immediate. If you define it as direct, the output would be:
before signal()
slot() called
after signal()
as expected. it doesn't generate any errors or warnings, and program doesn't crash as well.Yet this simple example doesn't prove it works for a large and complex one as well.
main.cpp:
#include <QtGui/QApplication>
#include "dialog.h"
#include "testssconnection.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestSignalSignalConnection * t = new TestSignalSignalConnection();
t->start();
return a.exec();
}
testssconnection.h:
#ifndef TESTSSCONNECTION_H
#define TESTSSCONNECTION_H
#include <QObject>
#include <QThread>
class TestSignalSignalConnection : public QThread
{
Q_OBJECT
public:
explicit TestSignalSignalConnection(QObject *parent = 0);
void run();
signals:
void signal1();
void signal2();
public slots:
void slot();
};
#endif // TESTSSCONNECTION_H
testssconnection.cpp:
#include "testssconnection.h"
#include <QtCore>
TestSignalSignalConnection::TestSignalSignalConnection(QObject *parent) :
QThread(parent)
{
}
void TestSignalSignalConnection::run()
{
TestSignalSignalConnection *t = new TestSignalSignalConnection();
this->connect(this,SIGNAL(signal1()),t,SIGNAL(signal2()), Qt::QueuedConnection);
t->connect(t,SIGNAL(signal2()), t,SLOT(slot()), Qt::DirectConnection);
qDebug() << "before signal()";
emit signal1();
qDebug() << "after signal()";
exec();
}
void TestSignalSignalConnection::slot()
{
qDebug() << "slot() called";
}
Take a look at qt-project, its a great wiki page about Threads and signals.
Threads, Events and QObjects::Signals and slots across threads