17
votes

I'm having a GUI/threading-related problem under Mac OS X (10.6.7). I'm using the wxWidgets framework (ver. 2.9.1), and it rests upon Cocoa in my case. The application design is like this:

  • thread #1 (a.k.a. "The Main Thread"): enters main(), parses switches, and if necessary, launches another thread (using the POSIX primitives).
  • thread #2 (a.k.a. "The GUI thread"): uses wxEntry to initialize wxWidgets and show the GUI.

Like most other GUI frameworks, Cocoa is not thread-safe, so we make sure to do all GUI calls from within thread #2, passing messages if required. Yet, in that particular case, an assertion is raised from within Cocoa's internals during initialization (from NSUndoManager to be more precise) saying in essence "it's not safe to use me outside the main thread". Even though thread #2 is the main thread as far as anything GUI-related is concerned.

Well, NSUndoManager has to have a way to find out it's running off the main thread (probably using NSThread::isMainThread()). So my question is: is it possible to trick NSUndoManager (and Cocoa in general) about this? And even better, to declare thread #2 being "The Main Thread", with thread #1 becoming a secondary one? Basically, I need an API call like "make the calling thread become the Main One". Undocumented wizardry and Objective C++ is fine, as long as it works on OS X 10.5 as well.

P.P. the code, as it is now, works flawlessly under Windows/Linux/MacOSX+Carbon. Also, redesigning it to change the thread structure would be a huge pain.

1
What is thread #1 doing during lifetime of application?John
Does [NSThread isMultiThreaded] return YES? You need to spawn at least one thread using NSThread for Cocoa to turn on multithreading support.LaC
Why do you not use the main thread for the GUI and other threads for the rest of the work?wilx
@John, thread #1 spawns a few other threads, and waits for events in some kind of an event loop. It basically organizes everything. @LaC, thanks for the pointer, I will check this out. @wilx, as I said, I can use the main thread for the GUI, but that would require a huge redesign, since in our case the GUI is optional - it may not be needed, but the application may still need to perform all the other work. In essence, GUI is only used for visualization of the work being done.anrieff
I don't know what the implementation details are that create this situation, but I recall at one point doing what you're doing (a GUI and event loop in a thread other than the one that calls main on Mac OS) and the system libraries would get horribly confused. As in, it would crash or deadlock at the very first GUI-related call. I would figure out a way to get yourself called from main. If you've designed your application well I'm not sure why it would be a "huge pain", so I would encourage you to think harder on it. The results would be better than hotpatching Cocoa or some such hackery.asveikau

1 Answers

1
votes

OK, so according to your comment: you basically won't escape refactoring of your code. Most GUI systems use main thread and handle event loops for themselves. But if you say that GUI is optional, maybe it'd better to split your application into two -- worker and GUI. GUI could communicate with worker via numerous ways, depending on platforms/specific needs.