Cleaning up after QApplication
Asked Answered
S

1

7

I'm porting a Qt desktop application to Linux (Ubuntu 19.10, 64bit desktop, Qt 5.12.5, gcc version 9.2.1), and am seeing some unexpected threads remaining alive after QApplication is finished.

Here's the minimum repro:

#include <QApplication>
#include <unistd.h>
int main(int argc, char * argv[]) {
    {
        QApplication app(argc, argv);
        sleep(1);
    }
    sleep(10);
    return 0;
}

If I debug the application at various points in time, here's what I see:

  • Before the constructor of QApplication is run, just one thread, the main thread, exists, as expected.
  • After the constructor of QApplication is run, 4 additional threads get created:
    • QXcbEventQueue
    • gmain
    • gdbus
    • QDBusConnection
  • After the destructor of QApplication is run, the QXcbEventQueue thread goes away.
  • Even after the second sleep of 10 seconds is done, the 3 other threads, besides the main thead, remain alive:
    • gmain
    • gdbus
    • QDBusConnection

I'm looking for a way to properly end these threads (and do other clean up that I might not be aware of at the moment) after QApplication has finished (of course, in the real app I call app.exec() and do other things) and has been destroyed.

This is not an issue in the application itself, which does not seem to have a problem with reaching the end of main with those 3 threads still alive.

The application is part of a larger suite of libraries / other applications that are thoroughly tested using Google Test, and the tests include some Death Tests, which, if executed after having run some tests that involve running a QApplication, complain about forking an application that has multiple threads, and get stuck and never finish, presumably, for this reason.

Any hints on how I might be able to get rid of those threads & perform a full cleanup after QApplication?

Stephniestepladder answered 4/1, 2020 at 18:26 Comment(0)
N
7

I'm looking for a way to properly end these threads

Short Answer.

You can't

Long Answer.

Those threads which are still remains active after destruction of QApplication are definitely created by QApplication but those threads are created with detached mode on. See for more info. When any thread created with detached mode on it neither can join nor set back to join-able.

To verify above check this code. This is point from where all integration plugins are created. Add break point here and step into code during debugging( in GDB). OR you can also set break point to function pthread_attr_setdetachstate.

Now coming to solution of problem.

Check this.

The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context.

So google-test library developers are well aware about problem you facing and they have solution for such case too. Look here

I believe this will helps you.

Noyes answered 7/1, 2020 at 10:14 Comment(1)
This answer is great and includes all the relevant references! There is only one aspect missing: Are there Qt-internal means to control these background threads? For example, QDBusConnection is executed in a QThread that would provide a quit() slot. This should work even for background threads, I presume? If Qt does not make use of such a mechanism, are there any insights as to why not? It seems insensible that platform integration plugins are left hanging around until termination of the executable, without registering any destruction logic...Narayan

© 2022 - 2024 — McMap. All rights reserved.