Am 23.01.2014 um 10:49 schrieb Sze Howe Koh <szehowe....@gmail.com>:
> On 23 January 2014 17:11, Till Oliver Knoll <till.oliver.kn...@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
_______________________________________________
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest