[Interest] Running Qt in a shared library on a Mac

Till Oliver Knoll till.oliver.knoll at gmail.com
Thu Jan 23 18:23:59 CET 2014


Am 23.01.2014 um 10:49 schrieb Sze Howe Koh <szehowe.koh at gmail.com>:

> On 23 January 2014 17:11, Till Oliver Knoll <till.oliver.knoll at gmail.com> wrote:
>> However "GUI thread" is a more correct term, since - AFAIK - the instance of
>> QApplication does not necessarily have to "live" in the "main thread": ...
> 
> This is true on Windows, Linux, and Carbon Mac.
> 
> But unless I've grossly misunderstood something, this is not true on
> Cocoa Mac: http://stackoverflow.com/questions/9761953/running-a-cocoa-gui-in-a-non-main-thread

Hmmm, bummer!
 
I did a quick google research and there are indeed discussions and blog entries – besides the one on Stack Overflow you posted – which really suggest that the NSApplication instance must live in the “main thread”, that is, really the thread where the main() entry function lives in.
 
Then there are other documents such as
 
   https://github.com/mpv-player/mpv/wiki/Cocoa-Constraints
 
which seem to confirm that, but make use of the words “is supposed to” (“Most of Cocoa UI, Event loop and Application classes are NOT thread safe and are /supposed to/ run in the main thread of the application”) and even suggest that it is possible to still instantiate NSApplication in a different thread (“Moving them out the main thread requires opening a connection to the window server manually: that is something in his right mind no one would do since it would be brittle and maintenance hell.”).
 
(Disclaimer for the following: I am not an experienced Cocoa developer - I use Qt for that ;))
 
However, I did not find any evidence in the Apple documents so far which would indicate that it is technically forbidden to instantiate an NSApplication (and call its “run method”) in a different thread than where the function main() lives in.
 
For instance:
 
 https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSApplication_Class/Reference/Reference.html
 
The “Overview” mentions that “Your program’s main() function should create this instance [of NSApplication] by invoking thesharedApplication class method.” – again the word “should” instead of “must”. And the following “The sharedApplication class method initializes the display environment and connects your program to the window server and the display server.” implies that it is really NSApplication:sharedApplication method which does the connection to the window manager, and not some Apple voodoo magic code which is run before the main() function (and which would hence technicaly /require/ that NSApplication be instantiated only in the thread where main() lives).
 
In fact, I believe that when the Apple documents talk about the “main thread” they really mean
 
  “The main thread is the one blocked in the run method of NSApplication, usually invoked in an application’s main function.”
 
See chapter “Event Handling Restrictions”
 
 https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html#//apple_ref/doc/uid/10000057i-CH12-123351-BBCFIIEB
 
“The thread being blocked in the run method of NSApplication” is, by that definition, not necessarily “the thread where function main() lives in”. And here again the word “usually” which implies “not always”.
 
 
So when put all the above together, in theory it should be possible to create an instance of NSThread in function main(), and within that thread create the shared instance of NSApplication (as described in the Apple NSApplication “Overview” documentation given above) and call its run method (the equivalent of QApplication::exec()). That newly created thread would then become the “main thread”, as soon as “run” is executing and processing all events, given my understanding of Apple’s definition of “main thread”. The method NSThread:isMainThread could also be helpful.
 
 
To bring this all a bit on-topic again: I did not know that creating a QThread is not possible without an instance of QApplication, but if the OP is willing to write some platform-specific code (which is easy: use “ObjC++” *.mm files as to mix ObjC with C++ and add those sources with OBJECTIVE_SOURCES += MyPlatformSpecificCode.mm to your project) the class NSThread could be used to spawn a new thread.
 
Then within that thread QApplication would be instantiated which eventually would instantiate NSApplication, and assuming that this NSApplication instance would have not been created previously (or after) already somewhere in main() (by some other code that the OP is executing before or after the thread creation) then that should work – again, in theory anyway ;)
 
 
If that fails, it would then be possible to “outsource” the whole GUI thread into its own process, start that process (with QProcess or whatever class is available at that time in main()) and communicate between “the GUI process” and the “main process” with e.g. local sockets and a custom (binary/textual) protocol (e.g. “command argument” based – or use JSON or whatever XML “dialect/protocol”).
 
  http://qt-project.org/doc/qt-5.0/qtnetwork/qlocalsocket.html
 
Or polling “state variables/messages” in shared memory:
 
  http://qt-project.org/doc/qt-5.0/qtcore/qsharedmemory.html
 
 
I once tried to implement “bi-directional communication” between parent-child processes with
 
  http://qt-project.org/doc/qt-5.0/qtcore/qprocess.html
 
alone, via stdin/stdout. That would be very nice, since you can treat a QProcess like a QIODevice and nicely read and write from/to it – in theory. But at least with Qt 4 I failed miserably at that time, and was told that “depending on the platform you’re totally lost and need platform-specific code”. I think especially on Windows that is a total PITA to get it right). But I can’t remember exactly what went wrong, write in one direction (probably child -> parent) did not work or the corresponding signals would not be emitted once data was available – anyway, I quickly gave up after some very convincing arguments here on qt-interest and am using local sockets now, which is much cleaner ;).
 
 
Cheers,
  Oliver
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20140123/de88e35b/attachment.html>


More information about the Interest mailing list