8

In the documentation for NSApplicationMain, it says:

Creates the application, loads the main nib file from the application’s main bundle, and runs the application. You must call this function from the main thread of your application [...].

The "main thread" obviously refers to the first thread of the program, where main(argc, argv) starts. A quick look through the NSThread documentation reveals + (BOOL)isMainThread, which can be used to determine whether the current thread is the "main" one or not. I ran some tests: this method works regardless of whether NSApplicationMain has been called yet.

My question has two (somewhat related) parts:

  1. What is so special about the main thread for NSApplicationMain?
  2. How does Cocoa identify the main thread in the first place?
Calvin
  • 2,872
  • 2
  • 21
  • 31
  • I'm thinking that whatever thread you call `NSApplicationMain` on becomes the "main" thread, where the run loop happens. – spudwaffle Sep 15 '11 at 13:55
  • This is not true. I tossed together a simple Cocoa application to test it. The app consists of (1) the main method which calls the `Forker` on a new thread, (2) the `Forker` that calls `NSApplicationMain`, and (3) a window controller that gets control once `NSApplicationMain` has done its thing. Each of these 3 prints whether it is on the main thread using the method mentioned above. Only (1) reports it is on the main thread, and the application crashes almost immediately. It does not crash when `NSApplicationMain` is called normally. – Calvin Sep 15 '11 at 16:11
  • Never mind then. @matthias's answer seems good. – spudwaffle Sep 16 '11 at 00:34

1 Answers1

7

Here is a good place to study NSApplicationMain by following a re-implementation of the function. NSApplicationMain must be called from the main thread primarily because

  1. It handles the primary interface
  2. UI elements (in several systems, not just OS X) need to all be called within the same thread to function correctly.
  3. Graphical elements provided within the Cocoa framework assume they'll be running in the main thread.

So pretty much, since Cocoa calls things in the main thread, and the UI needs to all be run in the same thread, you need to work within main thread for anything touching UI, including NSApplicationMain.

matthias
  • 2,419
  • 1
  • 18
  • 27
  • That's a good link! Thank you. All of these things sound correct, but what makes the "main" thread so special? Why not any old thread? It seems to me that as long as I confine my application to one thread, it shouldn't matter whether that thread was the first. Are there some system calls that only work from the main thread? (If so, why?) Are there any other libraries Cocoa might be using that have this restriction? I come from a Java background where all threads are created equal as long as you synchronize correctly. – Calvin Sep 16 '11 at 02:24
  • 1
    From what I've picked up from within the Cocoa documentation, it's simply that Cocoa assumes its on the main thread, and therefore probably specifically places its graphics functionality on the main thread. I think at least some unix graphical systems don't have this limitation (I've seen Qt discussions where graphics are running on a child thread), so it's probably Cocoa or one of its dependencies. – matthias Sep 16 '11 at 16:12
  • 1
    From what I've [read](http://stackoverflow.com/questions/4867839/how-can-i-tell-if-pthread-self-is-the-main-first-thread-in-the-process), it seems that many platforms don't even have a good way to identify the main thread. So I suppose the final answer is: BSD variants can identify the main thread, and Apple made the decision to make this thread special for Cocoa. My best guess for "why" is that it helps enforce threading restrictions. I guess we just have to live with it. Thanks for your help matthias! – Calvin Sep 17 '11 at 23:00
  • @Calvin — It's actually trivial to identify the main thread; "main thread" is just another name for the first thread in the program, the one where `_main` and `main` run. (All programs begin as single-threaded, and spawn new threads only in response to things that happen in `main` or its callees.) So Apple's `_main` routine can just mark its current thread as the main thread, and it'll be correct. Just because some platforms don't expose this information to the *user* doesn't mean that they don't have the concept of "main thread" at the *implementation* level. Everyone has a first thread. – Quuxplusone May 21 '13 at 18:08
  • 3
    The main thread is maintained by the pthreads implementation. On OS X, it provides the `pthread_main_np()` function. In various high-level frameworks, pthreads is consulted to make, for example, `CFRunLoopGetMain()` equal `CFRunLoopGetCurrent()` for the main thread. The first thread to ask for the main run loop causes it to be created and stashed in a shared variable, but only the main thread returns that run loop from `CFRunLoopGetCurrent()`. Etc. As a result, attempting to run `NSApplicationMain()` on another thread won't work right because that thread won't be running the main run loop. – Ken Thomases Dec 07 '13 at 06:51