18

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.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
anrieff
  • 619
  • 1
  • 6
  • 15
  • 2
    What is thread #1 doing during lifetime of application? – John May 30 '11 at 16:37
  • 2
    Does `[NSThread isMultiThreaded]` return `YES`? You need to spawn at least one thread using NSThread for Cocoa to turn on multithreading support. – LaC May 30 '11 at 19:26
  • 1
    Why do you not use the main thread for the GUI and other threads for the rest of the work? – wilx May 31 '11 at 07:08
  • 1
    @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 May 31 '11 at 16:44
  • 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 May 31 '11 at 17:34

1 Answers1

2

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.

John
  • 2,295
  • 1
  • 20
  • 25
  • 2
    Btw, the wxWidgets developers have assured me that, as far as wxWidgets is concerned, the thread that calls wxEntry() is *the main one*, and this allows you to use arbitrary thread structures inside your program, as long as all GUI processing only happens inside one thread (at least Win32 API, GTK and even Carbon on OS X allow you that). Yet Cocoa enforces this specific restriction, hence I posted this question here. So, I am kind of resigned to the prospect of redesigning my code. But of course, if a simple and quick hack would have done the trick, it would have been much better... – anrieff May 31 '11 at 20:21
  • @LaC, isMultiThreaded returns "yes", I did what is needed to protect the Cocoa framework, as described [here](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html%23//apple_ref/doc/uid/20000738-125024) – anrieff May 31 '11 at 20:28
  • 3
    You can create new thread at the very beginning of application's lifetime, call old `main()` in new thread and then instead of creating "GUI thread", use main thread as GUI thread. – John May 31 '11 at 21:54