I've got some Asynchronous cleanup activity I need to do as my Qt application is shutting down.
My current approach is to trap the aboutToQuit signal. I launch my Asynchronous behavior, and then the application shuts down. Is there any way to block Qt from shutting down until my asynchronous behavior is complete?
This works on windows by trapping the main window's closeEvent and calling ignore() on the event. But on Mac, when a user quits, my ignore() isn't honored, and the Application shuts down before my asynchronous activity is complete.
Thanks.
Why do you launch your cleanup code asynchronously if you have to wait anyway until your code is done?
If you don't connect your slot as QueuedConnection to aboutToQuit it should block until your cleanup code is done.
But if you really want launch it asynchronously you have to synchronize it by hand:
QSemaphore wait4CleanupDone;
class MyQuitHandler { ... public slots: void handleQuit(); ... } myQuitHandler;
void MyQuitHandler::handleQuit() { ... ; wait4CleanupDone.release(); }
int main(int argc, char** argv) {
QApplication app(argc, argv);
QObject::connect(&app, SIGNAL(aboutToQuit()), &myQuitHandler, SLOT(handleQuit()));
...
int result = app.exec();
wait4CleanupDone.acquire();
return result;
}
But note, that your asynchronous code might be ignored in some cases anyway:
"We recommend that you connect clean-up code to the aboutToQuit() signal, instead of putting it in your application's main() function. This is because, on some platforms the QApplication::exec() call may not return. For example, on the Windows platform, when the user logs off, the system terminates the process after Qt closes all top-level windows. Hence, there is no guarantee that the application will have time to exit its event loop and execute code at the end of the main() function, after the QApplication::exec() call."
From: http://doc.trolltech.com/4.6/qapplication.html#exec
Crashes here regrettably when i try this.
problem is the connect call where it alraedy crashes line 3 of main.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QObject::connect((QObject *)&app, SIGNAL(aboutToQuit()), (QObject *)&myQuitHandler,
SLOT(QuitApp()), Qt::QueuedConnection );
QGraphicsScene scene(QRectf(0, 0, 640, 480));
..
}
After i started using qgraphicsscene not a single signal works anymore as i get it not connected in a manner that any signal works.
So far could solve everything, how to solve this without 'connect' ?
Crash i get here is instant:
Invalid parameter passed to C runtime function.
exited with code -1073741819
Related
For different reasons I have to create a QApplication that does not live in the main thread of my program. This works well except for the cleanup part. Once main() finishes I get the following notification:
QObject::~QObject: Timers cannot be stopped from another thread
This happens quite some time after all Qt widgets and windows as well as the QApplication have been disposed of.
I narrowed the problem down to this minimal example:
#include <thread>
#include <QApplication>
#include <QLineEdit>
int main(int argc, char * argv[])
{
std::thread t {
[&] {
QApplication app{argc, argv};
QLineEdit w{"Test"};
w.showNormal();
app.exec();
}
};
std::this_thread::sleep_for(std::chrono::seconds{3});
QApplication::instance()->quit();
t.join();
return 0;
}
A QSpinBox instead of a QLineEdit leads to the same behavior. When I use a QLabel however, no warning is issued. So I suspect that the culprit is a timer responsible for cursor flashing but I might be wrong here.
Is there any way to stop this (invisible) timer correctly when quitting the QApplication?
I would also be happy with manually posting something like a QuitEvent
in the application's event loop instead of calling quit()directly.
Here you go:
QMetaObject::invokeMethod(QApplication::instance(), "quit", Qt::QueuedConnection);
You are not allowed to access widgets and other related elements from anywhere but the main thread. This is common with nearly all GUI systems (e.g. MFC, BGI, ...).
For Qt there is a hint on this in the documentation. Surprisingly enough not even a QPixmap is allowed in worker threads.
I am currently coding a program in C++/ Qt 5.9 to control a 3D Printer.
I have divided the project into several libraries :
The GUI Lib: The view
The Device Lib: Control each device (movement, printing tool, sensors)
The Controller Lib: Links the View with the Device lib
etc...
My problem is that I do not know how to initialize and terminate properly the execution of the program. More specifically, the Device library has a class named DeviceManager with two functions :
initialize() : which connect to each device and initialize them. This actions can take several seconds (10s for example)
finalize() : which closes all the connexions, can also take several seconds
What I would like to do is initialize the Device Lib in the right place without blocking the GUI and then finalize it in the right and not block the GUI
This is my main code :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
My solution now is to call DeviceManager::initialize() in the MainWindow constructor and DeviceManager::finalize() in the MainWindow::closeEvent().
The problem: even if I use concurrency to initialize and finalize in a different thread, the application displays its window several seconds after it was launched and the display freezes when the application is closed because it has to wait for the finalize function to be done.
How should I properly handle this initialization and finalization problem, please ? Do I need to reimplement the QApplication class? Do I try and do it in the main? Do you know any great example of an open source application doing that kind of initialize and finalize work?
The problem: even if I use concurrency to initialize and finalize in a different thread, the application displays its window several seconds after it was launched and the display freezes when the application is closed because it has to wait for the finalize function to be done.
You could start the initialize() function as own detached thread before starting the MainWindow. This could cause problems if the initializing thread doesn't terminate before the first initialized "thing" is needed. Something like:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
std::thread{initialize}.detach();
MainWindow w;
w.show();
finialize();
return a.exec();
}
To prevent the problem, and maybe lock some function in the GUI, then you probably need to have a state variable that it sets under a mutex on its way out, and which you examine under a mutex to see if it has been set.
According this article here, is it Ok to say that, when we close a Qt programm. Once the mainWindow's close event started, nothing else except the close event handler and class deconstructor in the GUI thread will be executed?
For example, if there is a QTimer fired the timeout() signal in the GUI thread to a slot in the same thread. When the mainWindow's close event started, the slot will not get any chance to be executed again?
No, it is wrong on its face to say that once the mainWindow's close event started, nothing else will execute in the GUI thread except the close event handler and class destructors.
Suppose we have following code (in C++11):
#include <QApplication>
#include <QLabel>
#include <QMessageBox>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label1("Hello, World!");
label1.show();
label1.setMinimumSize(200, 100);
app.exec();
QTimer timer;
int counter = 0;
QObject::connect(&timer, &QTimer::timeout, [&counter]{ counter ++; });
timer.start(100);
QMessageBox::information(nullptr, "Done",
QString("We're Done with \"%1\"").arg(label1.text()));
QMessageBox::information(nullptr, "Really Done",
QString("Timer has ticked %1 times").arg(counter));
return 0;
}
Obviously, non-destructor code will execute after exec() has returned - here we show a message box. The main window, in this case a QLabel, still exists after exec() has returned.
It is also incorrect to assume that somehow the timers will be globally killed after exec() has returned. They're still running, and as long as you re-start the event loop, they'll gladly fire for you. The second message box will display a non-zero count, after all.
Your question should be reworded with the problem you're trying to solve. You're asking for very specific details that make little sense on their own. Please tell use why you ask such a question.
It's handled automatically:
QObject::~QObject()
All signals to and from the object are automatically disconnected, and
any pending posted events for the object are removed from the event
queue. However, it is often safer to use deleteLater() rather than
deleting a QObject subclass directly.
However for multi-threaded apps you need to use deleteLater() to avoid crashes:
Warning: Deleting a QObject while pending events are waiting to be
delivered can cause a crash. You must not delete the QObject directly
if it exists in a different thread than the one currently executing.
Use deleteLater() instead, which will cause the event loop to delete
the object after all pending events have been delivered to it.
Do I miss any Qt functionality if I substitute QApplication::exec() with standard Windows message loop implementation? This should clarify what I mean:
The ususal “Qt” way to run event processing:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
“Windows” way to run event processing:
#include <Windows.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
MSG msg;
while(GetMessage(&msg, 0, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
The above demonstrates having external message loop with respect to QApplication instance, while QApplication instance itself doesn’t even have its own event loop at all.
In other words, if I have main.exe program (knowing nothing about Qt) with message loop and a .dll with Qt GUI and QApplication instance inside, will it be ok to let the external message loop from main.exe to handle events for Qt GUI?
Thanks in advance!
EDIT 1:
I’ll just answer myself in case it’s usefull for somebody:
We have a main .exe module written in C# under .NET that runs event loop processing, and we have a couple of .dlls written in Qt/C++ that have a GUI “inside” (and a QApplication instance that is shared). QApplication::exec() is never called but all the events are successfully dispatched by the main .exe (.NET) module’s event loop and all the Qt functionallity is present( signals/slots, threads, etc.)
EDIT 2:
That worked for Qt 4.8.2 but for Qt 5.1.0 things are a little bit different. Now you have to call QApplication::processEvents() once because it performs some initial initialization on its first call( installs WindowsHook on GetMessage or PeekMessage ). And after that whoever calls GetMessage in your application Qt events get processes and you are golden :)
The first thing which comes to my mind is that calling slots across threads won't work because the Qt event loop is executing those calls.
But the more important question is probably: Why do you want to do it like this especially since in qeventdispatcher_win.cpp is doing essentially the same thing?
I will keep the code simple so that you guys can see what I'm trying to do ;)
I am aware of all of the locking issues, etc. I'm trying to figure out how signals and slots play with threads.
In main.cpp:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyConsole c; // Subclasses QThread and implements run()
MyReceiver r(app); // We pass app to MyReceiver for later (see below)
QObject::connect(&c, SIGNAL(sendit()),
&r, SLOT(gotit()));
c.start(); // Start the worker thread
app.exec();
}
Assume that the signals and slots were properly set up in the header files (I've tested and they are). Now, here's the issue:
In MyReceiver.cpp:
void MyReceiver::gotit()
{
QLabel *label = new QLabel(0, "Hello"); // Some GUI element, any will do
app.setMainWidget(*label); // Some GUI action, any will do
}
The question is: Because the MyReceiver object was created in main(), which is on the main thread, does that mean that the slots (e.g., gotit()) will run on the main thread and are therefore safe for doing GUI stuff? Even in cases where the signal was raised from a different QThread (like MyConsole in this example)?
Is there a better way to allow worker threads to interact with the GUI (for example, Obj-C/Cocoa have a "send message on main thread" type of approach). What is "The Qt way" of doing this?
Thanks in advance!
By default (Qt::AutoConnection), slots will run in the thread the QObject was created in. So, no matter from what thread you emit the signal, the slot will be run always in the thread, the QObject "lives" in (if a Qt event loop is running in that thread, otherwise the event can't be delivered). Since the main thread will become the Qt GUI thread, this will work as expected. This is indeed the Qt way of interacting with the GUI.
See also: http://doc.qt.nokia.com/4.7/thread-basics.html (look for thread affinity).
The "Qt way" to emit a signal from one thread and receive it in a different thread is to use a Queued connection
connect( obj, SIGNAL(foo()), other_obj, SLOT(bar()), Qt::QueuedConnection )
From the Qt documentation for Qt::QueuedConnection:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.