2

I am trying to use Qt as a library (similar to this), because I want to reuse Qt classes in some currently non-Qt applications, and in shared libraries as cross-platform glue. Everything is non-GUI.

Some problems are easily avoided by DirectConnection, some can be solved with private event loops, even one can run a fake QCoreApplication in a thread and it works (last resort).

I want to know what modules rely on a running instance of QCoreApplication and cannot work without it.

Some of the Qt modules (in QtCore) do need an instance of QCoreApplication to run properly. For example QTimer relies on QCoreApplication to dispatch timer events. I was reading the documentation for QtConcurrentRun and it seems to be relying on a global instance of QThreadPool, I am about to try and see if the application execution is vital, or maybe the instance is created on first access, or maybe not.

I am going to study QCoreApplicationPrivate source (Windows and Linux for now) but any hints in the right direction is greatly appreciated.

What are other functionality dependencies to the core application? Note that it might depend on the OS.

Edit1: Thanks to Kuba's answer, It seems QCoreApplication event loop is not necessary for timer and socket events to be dispatched. So some QtCore modules require and instance of QCoreApplication, but there is no need to have a running application event loop.

Community
  • 1
  • 1
dashesy
  • 2,596
  • 3
  • 45
  • 61

1 Answers1

3

You are conflating the existence of a QCoreApplication with a running event loop. Those two are separate concepts. You may well need the former for the latter, but the latter doesn't have to run in the same thread as the former.

Most notably, you don't really have to call qApp->exec() if you don't have any events to dispatch in the thread where you constructed QCoreApplication.

The existence of a QCoreApplication is, as it were, a non-issue. Things get hairier with QApplication -- you can start it in a non-gui thread, but it's not portable and won't work on OS X. I'm trying to figure out why it doesn't work, but I don't have much time now to offer a satisfactory solution -- not yet.

It is also a misconception that QCoreApplication's event loop needs to be running for socket notifications and timer events to be dispatched to other threads. A QCoreApplication's event loop is nothing special. There is a platform-specific instance of QAbstractEventDispatcher that gets created for a thread when you instantiate the first QEventLoop in that thread. The QEventLoop doesn't know anything specific about the platform.

QCoreApplication's exec() method is quite simple and creates an instance of QEventLoop, and thus will create an instance of platform-specific QAbstractEventDispatcher. This instance is not special in any way. It's the same as any other event dispatcher created in any other thread, as far as my code reading tells so far.

If all underlying window systems would support it, it'd be in fact possible to make Qt GUI code multithreaded -- the per-thread event reception and dispatch is already there as a small first step. The big obstacle, probably the only one, would be the X library and its display lock. The display lock would be an obvious matter of contention between threads. You'd need each thread that wants to talk to the GUI open up a separate connection to the X server, and I don't know if there's a supported way of doing that from Xlib.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • +1 for the insight. Some of QCore function may only need non-NULL *QCoreApplication::instance()* but not necessarily the event loop running. Some (like timer) need the application event loop. – dashesy Jun 06 '12 at 23:32
  • I don't think it's true that timers need the application event loop. A timer only needs a running event loop in the thread where you're consuming the timer's output. If you have QObject in thread B, and QApplication in thread A, you're free to use QTimer in thread B, connect its `timeout()` signal to your QObject instance's slot. You must run the event loop in thread B, of course. – Kuba hasn't forgotten Monica Jun 06 '12 at 23:55
  • 1
    this what the comments in QCoreApplication says: QCoreApplication contains the main event loop, where all events from the operating system (e.g., timer and network events) and other sources are processed and dispatched. – dashesy Jun 07 '12 at 13:54
  • Also in *QEventDispatcherWin32Private::sendTimerEvent* this is how timer events are propagated: *QCoreApplication::sendEvent*. I should also look at the Linux version to see if this is only Windows – dashesy Jun 07 '12 at 14:08
  • A sendEvent won't get sent to a different thread, though, so if QCoreApplication only does sendEvent, it wouldn't work. I'll simply have to try it out. – Kuba hasn't forgotten Monica Jun 07 '12 at 17:57
  • @dashesy I don't know in what version of Qt you were reading the comments and whatnot, but it'd be entirely silly if timers were not supported natively per thread -- everything would be slaved to the GUI thread. I've looked at the code, and there's an instance of QAbstractEventDispatcher per each *thread*. It's the event dispatcher that has an internal OS-specific handles needed to consume timer and network events from the OS. A QCoreApplication doesn't by itself receive anything. It merely starts a QEventLoop, and that one will create an event dispatcher for the current thread if none exists. – Kuba hasn't forgotten Monica Jun 08 '12 at 02:05
  • It is Qt 4.8.1 and the comment is from src/corelib/kernel/QCoreApplication.cpp – dashesy Jun 08 '12 at 14:25
  • Qt 4.8.1, the comment is from src/corelib/kernel/qcoreapplication.cpp also if you look at qt_internal_proc in qeventdispatcher_win.cpp at the very beginning there is a `if (!app) ... return 0` which means the event handler needs global instance of the app to be instantiated. Also look at qt_fast_timer_proc there for mmtimer code path. My question here might be; what in core is slave to app thread. It might be Windows, but in my application I assume it is the same for all because it is supposed to be cross platform, and is not documented. – dashesy Jun 08 '12 at 14:57
  • The application must be instantiated, but nobody cares if its event loop is running. Nothing in core seems to be "slave" to app thread. – Kuba hasn't forgotten Monica Jun 08 '12 at 17:00
  • After reading the code and trying it, it seems that you are right, thanks. I think the mentioned comment confused me, I saw timers were not firing, read that comment, added the code to instantiate app and run it in a separate thread and timers were working, I did not guess only the instance might be enough. – dashesy Jun 08 '12 at 18:06
  • The explanation in the "display lock" link is stupid. It's obvious that one socket connection cannot be used by multiple threads. And the obvious solution is to allow more than one connection from the same client, as the comment underneath that post correctly indicates... – BartoszKP Jul 17 '14 at 10:17
  • @BartoszKP It's not about the socket - that's an implementation detail. The xlib could, if it only chose to, provide multi-threaded access to its data structures, and to the server, via a single coket. I wrote a multi-threaded minimal xlib a long time ago, and it can be done without a global lock. It can even perform reasonably well. The interface to the socket was scatter-gather over per-thread request queues. I only imagine getting rid of display lock in the most popular xlib implementation would take a lot of refactoring. – Kuba hasn't forgotten Monica Jul 17 '14 at 18:55
  • @KubaOber That's another way to do it, but you need the lock on the socket. Anyway, this only makes the linked post even more stupid :) – BartoszKP Jul 17 '14 at 20:10