Faced the problem of sending a signal from one thread to the main thread.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
ThreadsManagement management;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("eventHandler", management.getEventHandler());
engine.addImportPath("qrc:/");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
In the main thread I create an object that is responsible for other threads with objects.
Further, from it I get a pointer to the object (EventHandler) that I have through signals and slots communicates with the GUI. From it(EventHandler) I send data to the QML and I need to respond to certain signals in it.
Connections
{
target: eventHandler
function onSignalAlertUserExists()
{
console.log("user exists");
}
}
So, I need to respond to the signalAlertUserExists() signal already in the main thread. But I get an error
QQmlEngine: Illegal attempt to connect to EventHandler(0x55920259e4e0) that is in a different thread than the QML engine QQmlApplicationEngine(0x7ffe13052540.
I understand that the main thread cannot receive a signal from another thread, but I do not understand how to solve this problem.
Thanks in advance for those who respond
Thx.
Related
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.
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();
}
I need to show a messagebox to user from my static library but using QMessageBox needs QApplication;
How can I show a message box without QApplication?
Just instantiate an instance of QApplication for the lifetime of the app. (e.g. in your "main", "WinMain", or somewhere early in your app initialization sequence)
From then on, you can create modal instances of QMessageBox all you want. It should co-exist fine with your own message pump as long as you are using a recent version of Qt.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msgBox;
msgBox.setText("Hello World");
msgBox.exec(); // blocks until the user finishes interacting with the message box
return 0;
}
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 have a weird qt problem: My application doesn't quit in some configurations.
The idea is to have a program, which can be started as a program with a GUI (through myWindow) or as a pure console application (controlled via myConsole, which runs its own loop in its thread to record keyboard inputs). Either way quitting is done by calling the myObject slot quitMyObject, which in turn cleans up some objects and emits the signal signalQuitapplication, which is connected to the QApplication (app) quit slot.
Unfortunately the application only quits when the the window is enabled and the quit command is entered in the console (although the slotQuitMyObject of myObject is always called). So I wonder what criterions Qt has to actually quit the main event loop and exit the program.
The code looks like this:
int main(int argc, char *argv[])
{
bool enableWindow = false;
QApplication app(argc, argv, enableWindow);
MyUiAbstract* myConsole = new ConsoleUi(); // ConsoleUi inherits from MyUiAbstract, which inherits from QThread
MyWindow* myWindow = NULL; // MyWindow inherits from QMainWindow
if(enableWindow)
{
myWindow = new MyWindow();
myWindow->show();
}
MyObject* myObject = new MyObject(myConsole, myWindow, ...);
QObject::connect(myObject, SIGNAL(signalQuitQApplication()), &app, SLOT(quit()), Qt::QueuedConnection);
QObject::connect(myConsole, SIGNAL(signalQuitMyObject()), myObject, SLOT(slotQuitMyObject()), Qt::QueuedConnection);
QObject::connect(myWindow, SIGNAL(signalQuitMyObject()), myObject, SLOT(slotQuitMyObject()), Qt::QueuedConnection);
QObject::connect(myWindow, SIGNAL(signalQuitConsoleUI()), myConsole, SLOT(slotQuitMyUi()), Qt::QueuedConnection);
return app.exec();
}
Try to use that code in your MyConsole class:
#include <QApplication>
...
qApp->quit();
Also you need to close all the event loops & threads before quit.