QObjects can easily become threadless, when their work thread finishes ahead of them. When this happens, Qt doesn't release their timer ids, even though the timers are not active anymore. Thus, a QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning appears. It has mostly cosmetic consequences, but does indicate a timer id leak, and thus a workaround would be nice to have. The following example triggers the problem:
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
app.exec();
workThread.quit();
workThread.wait();
}
It'd be nice if the workaround didn't have to make any modifications to how the timers are allocated, i.e. that there would be no extra tracking of timers needed beyond what Qt already does.
A simple solution is to prevent the problem: if the object is about to become threadless, move it to the thread handle's parent thread, and then when the thread itself is about to be destructed, reestablish the object's timers to prevent the warning.
QObject's moveToThread implementation has two parts:
The QEvent::ThreadChange is delivered to the object from moveToThread. QObject::event uses this event to capture and deactivate the timers active on the object. Those timers are packaged in a list and posted to the object's internal _q_reactivateTimers method.
The event loop in the destination thread delivers the metacall to the object, the _q_reregisterTimers runs in the new thread and the timers get reactivated in the new thread. Note that if _q_reregisterTimers doesn't get a chance to run, it will irrevocably leak the timer list.
Thus we need to:
Capture the moment the object is about to become threadless, and move it to a different thread, so that the QMetaCallEvent to _q_reactivateTimers won't be lost.
Deliver the event in the correct thread.
And so:
// https://github.com/KubaO/stackoverflown/tree/master/questions/qbasictimer-stop-fix-50636079
#include <QtCore>
class Thread final : public QThread {
Q_OBJECT
void run() override {
connect(QAbstractEventDispatcher::instance(this),
&QAbstractEventDispatcher::aboutToBlock,
this, &Thread::aboutToBlock);
QThread::run();
}
QAtomicInt inDestructor;
public:
using QThread::QThread;
/// Take an object and prevent timer resource leaks when the object is about
/// to become threadless.
void takeObject(QObject *obj) {
// Work around to prevent
// QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
static constexpr char kRegistered[] = "__ThreadRegistered";
static constexpr char kMoved[] = "__Moved";
if (!obj->property(kRegistered).isValid()) {
QObject::connect(this, &Thread::finished, obj, [this, obj]{
if (!inDestructor.load() || obj->thread() != this)
return;
// The object is about to become threadless
Q_ASSERT(obj->thread() == QThread::currentThread());
obj->setProperty(kMoved, true);
obj->moveToThread(this->thread());
}, Qt::DirectConnection);
QObject::connect(this, &QObject::destroyed, obj, [obj]{
if (!obj->thread()) {
obj->moveToThread(QThread::currentThread());
obj->setProperty(kRegistered, {});
}
else if (obj->thread() == QThread::currentThread() && obj->property(kMoved).isValid()) {
obj->setProperty(kMoved, {});
QCoreApplication::sendPostedEvents(obj, QEvent::MetaCall);
}
else if (obj->thread()->eventDispatcher())
QTimer::singleShot(0, obj, [obj]{ obj->setProperty(kRegistered, {}); });
}, Qt::DirectConnection);
obj->setProperty(kRegistered, true);
}
obj->moveToThread(this);
}
~Thread() override {
inDestructor.store(1);
requestInterruption();
quit();
wait();
}
Q_SIGNAL void aboutToBlock();
};
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
QObject object1, object2;
object1.startTimer(10);
object2.startTimer(200);
Thread workThread1, workThread2;
QTimer::singleShot(500, &QCoreApplication::quit);
workThread1.start();
workThread2.start();
workThread1.takeObject(&object1);
workThread2.takeObject(&object2);
app.exec();
}
#include "main.moc"
This approach can be easily extended to dynamically track all children of obj as well: Qt provides sufficient events to do such tracking.
Hold the timer id to be killed from within thread - by object:
int id = object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
QObject::connect(&workThread, &QThread::finished, [&](){object.killTimer(id);});
...
How about moving the object back to the main thread...
class Object : public QObject
{
public:
using QObject::QObject;
virtual ~Object() {
qDebug()<<"Object"<<QThread::currentThread()<<this->thread();
if(thread() == Q_NULLPTR)
moveToThread(QThread::currentThread());
}
};
#include <QtCore>
int main(int argc, char *argv[]) {
static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
QCoreApplication app(argc, argv);
Object object;
object.startTimer(1000);
QThread workThread;
workThread.start();
object.moveToThread(&workThread);
QTimer::singleShot(500, &QCoreApplication::quit);
qDebug()<<"main"<<QThread::currentThread()<<object.thread();
app.exec();
workThread.quit();
workThread.wait();
}
Related
I've wrote this code looking at examples online of how I'm supposed to run a console program that doesn't just run and quit and one that does. Based on a Qt console application. This one here, I wanted it to quit. I've understood pretty much everthing excepth the QTimer::singleShot line. If the line is commented out, the application will run but will not quit. If it is left, the application will run and quit as expected. Can anyone explain to me why?
dostuff.h
#ifndef DOSTUFF_H
#define DOSTUFF_H
#include <QObject>
#include <iostream>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0);
public slots:
void run();
signals:
void finished();
};
#endif // DOSTUFF_H
And the implementation dostuff.cpp
#include "dostuff.h"
DoStuff::DoStuff(QObject *parent):QObject(parent)
{
}
void DoStuff::run(){
for (int i = 0; i < 10000; i++){
std::cout << "Processing " << i << std::endl;
}
emit(finished());
}
My main.cpp
#include <QCoreApplication>
#include <QTimer>
#include "dostuff.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
DoStuff *dostuff = new DoStuff(&a);
QObject::connect(dostuff,SIGNAL(finished()),&a,SLOT(quit()));
dostuff->run();
// WHY THIS??
QTimer::singleShot(10,dostuff,SLOT(run()));
return a.exec();
}
QTimer is not required to exit properly; You just need to provide a way to get your application to break the event loop at some point. In GUI application, Qt does that automatically when the last window is closed.
In Console applications, you can:
Either run your application without an event loop (if you have a straight-forward simple control flow in your application).
Or (if you require an event loop to handle some events or cross thread signal/slots) you need to have some event that makes your application break the event loop and quit. This event should only be triggered when the application has finished its job.
The code sample you have in your question is really simple, and does not require an event loop to run properly. The only effect the QTimer has in your code is that it delays execution for 10 ms. Here is the same code sample without running an event loop:
#include <QtCore>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0) : QObject(parent) {}
public slots:
void run() {
for (int i = 0; i < 10000; i++){
qInfo() << "Processing " << i;
}
emit finished();
}
signals:
void finished();
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
DoStuff dostuff;
QObject::connect(&dostuff, &DoStuff::finished,
&a, &QCoreApplication::quit);
dostuff.run();
return 0; //no event loop required
}
#include "main.moc"
If you start an event loop, you may notice that the quit slot does not work when not using QTimer::singleShot. The reason for this is that quit is called before the event loop is even started (and the call has no effect at all). That's why according to the docs, it is recommended to connect to quit using a queued connection:
It's good practice to always connect signals to this slot using a QueuedConnection. If a signal connected (non-queued) to this slot is emitted before control enters the main event loop (such as before "int main" calls exec()), the slot has no effect and the application never exits. Using a queued connection ensures that the slot will not be invoked until after control enters the main event loop.
So, if you want to have an event loop in your code above, you just need to connect using a Qt::QueuedConnection:
#include <QtCore>
class DoStuff: public QObject
{
Q_OBJECT
public :
DoStuff(QObject *parent = 0) : QObject(parent) {}
public slots:
void run() {
for (int i = 0; i < 10000; i++){
qInfo() << "Processing " << i;
}
emit finished();
}
signals:
void finished();
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
DoStuff dostuff;
QObject::connect(&dostuff, &DoStuff::finished,
&a, &QCoreApplication::quit,
Qt::QueuedConnection);
// ^^^^^^^^^^^^^^^^
// use a queued connection
dostuff.run();
return a.exec(); //start an event loop
}
#include "main.moc"
Timer is needed to postpone execution. Since you want to have a running event loop, a.exec() has to be called, then the timer executes your code. When your code finishes running, it triggers finished signal, that is tied to QCoreApplication::quit - that's the needed exit for event loop running inside a.exec().
Btw, you have to remove: dostuff->run(); from your code.
In some Qt examples, I see they use
QTimer::singleShot(0, this , SLOT(funcA())), why not to call the slot funcA directly? also the same question for using QMetaMethod::invoke to call function with parameters.
The following lines are all functionally equivalent:
QTimer::singleShot(0, object, &Class::funcA); // Qt 5
QTimer::singleShot(0, object, SLOT(funcA())); // Qt 4
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
As is now apparent, the intent is to execute the call within the event loop. The queued call results in the posting of an QMetaCallEvent to the object. This event is handled by QObject::event and results in the call of the desired method. Thus, the following are exactly equivalent, even if the latter is a private implementation detail - letting me skip the details of instantiating the event:
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
QCoreApplication::postEvent(object, new QMetaCallEvent{...});
This comes handy in various situations. For example:
To execute some code after all hitherto posted events have been handled.
To execute only after the event loop has started.
To call an invokable method that's not accessible due to C++ access modifiers. The invokable methods are: signals, slot, and methods declared Q_INVOKABLE.
The direct call is unsafe (read: an error!) when a QObject resides in another thread, unless you're explicitly calling a method documented as thread-safe.
The queued call is a necessity if you wish to ensure that an event loop quits immediately: a direct quit() call is a no-op if the loop is not running yet.
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
app.quit(); // this is a no-op since the event loop isn't running yet
return app.exec(); // will not quit as desired
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec(); // will return immediately
}
Ideally, you'd use postToThread from this answer, it offers the lowest-cost way of calling methods in other threads:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
postToThread([]{ qApp->quit(); });
}
An alternative way of doing it is using a QObject as a signal source:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
{
QObject src;
src.connect(&src, &QObject::destroyed, &app, &QCoreApplication::quit,
Qt::QueuedConnection);
}
return app.exec(); // will return immediately
}
Yet another way would be to use a custom event and act in its destructor:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
struct QuitEvent : QEvent {
QuitEvent() : QEvent(QEvent::None) {}
~QuitEvent() { qApp->quit(); }
};
QCoreApplication::postEvent(&app, new QuitEvent);
return app.exec(); // will return immediately
}
Every system has a event loop where events are processed. Say like
application::processEvents()
{
// process event list..
}
Now the place where you write QTimer::singleShot(0, this, SLOT(doSomething())); might be inside some processing event.
When this loop is done, processEvents will be called again and in that the doSomething() will be executed.
So this is like calling doSomething in the next event loop, rather than calling it immediately.
Hope you get the idea.
These methods can also be used to invoke protected and private members of a class (if they are defined as slots) from a scope that would otherwise require public access.
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.
I derived an application class from QApplication in order to reimplement some methods.
Here is the code:
class MyApplication : public QApplication
{
Q_OBJECT
private:
public:
//...
virtual ~MyApplication();
};
MyApplication::~MyApplication()
{
qDebug("~MyApp1");
try
{
//some potentially long operations
}
catch(...)
{
qDebug("~MyApp Exception");
}
qDebug("~MyApp2");
}
int main(int argc, char *argv[])
{
int returnValue = 1;
{
MyApplication app(argc, argv);
returnValue = app.exec();
}
return returnValue;
}
The problem is that I tend to get different qDebug outputs. I always get ~MyApp1 printed, but only sometimes ~MyApp2. What could be the reason? It seems, that when the App is closing, Qt does not let the whole destructor to be done. How can I make the program wait till the destructor is finished?
The QApplication Destructor is called properly, it's just that qDebug probably shouldn't/can't be used at such a late state of the application. Try using cout/cin streams directly (iostreams/printf).
I am new to QT and I am doing some learning.
I would like to trigger a slot that modify a GUI widget from a C++ thread(Currently a Qthread).
Unfortunatly I get a: ASSERTION failed at: Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
here is some code:
(MAIN + Thread class)
class mythread : public QThread
{
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
w->ui.textEdit->append("Hello"); //<--ASSERT FAIL
//I have also try to call a slots within mywindow which also fail.
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
thr->start();
return a->exec();
}
Window:
class mywindow : public QMainWindow
{
Q_OBJECT
public:
mywindow (QWidget *parent = 0, Qt::WFlags flags = 0);
~mywindow ();
Ui::mywindow ui;
private:
public slots:
void newLog(QString &log);
};
So I am curious on how to update the gui part by code in a different thread.
Thanks for helping
stribika got it almost right:
QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
Q_ARG( QString, myString ) );
cjhuitt's right, though: You usually want to declare a signal on the thread and connect it to the append() slot, to get object lifetime management for free (well, for the price of a minor interface change). On a sidenote, the additional argument:
Qt::QueuedConnection ); // <-- This option is important!
from cjhuitt's answer isn't necessary anymore (it was, in Qt <= 4.1), since connect() defaults to Qt::AutoConnection which now (Qt >= 4.2) does the right thing and switches between queued and direct connection mode based on QThread::currentThread() and the thread affinity of the receiver QObject at emit time (instead of sender and receiver affinity at connect time).
In addition to stribika's answer, I often find it easier to use a signal/slot connection. You can specify that it should be a queued connection when you connect it, to avoid problems with the thread's signals being in the context of its owning object.
class mythread : public QThread
{
signals:
void appendText( QString );
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
emit ( appendText( "Hello" ) );
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
(void)connect( thr, SIGNAL( appendText( QString ) ),
w->ui.textEdit, SLOT( append( QString ) ),
Qt::QueuedConnection ); // <-- This option is important!
thr->start();
return a->exec();
}
You need to use QMetaObject::invokeMethod. For example:
void MyThread::run() {
QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello"));
}
(The above code comes from here: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)
I don't think you are allowed to call directly things that results in paint events from any
other threads than the main thread. That will result in a crash.
I think you can use the event loop to call things asynchronously so that the main gui thread picks up and then does the updating from the main thread, which is what cjhuitt suggests.