Почему в Apple Cocoa API важно, чтобы NSApplicationMain вызывался из основного потока?

В документации для NSApplicationMain, он говорит:

Создает приложение, загружает основной файл пера из основного пакета приложения и запускает приложение. Вы должны вызывать эту функцию из основного потока вашего приложения [...].

«Основной поток», очевидно, относится к первому потоку программы, где начинается main(argc, argv). Краткий обзор NSThread документация раскрывает + (BOOL)isMainThread, который можно использовать для определения того, является ли текущий поток «основным» или нет. Я провел несколько тестов: этот метод работает независимо от того, был ли уже вызван NSApplicationMain.

Мой вопрос состоит из двух (несколько связанных) частей:

  1. Что такого особенного в основном потоке для NSApplicationMain?
  2. Как Cocoa в первую очередь идентифицирует основной поток?

person Calvin    schedule 15.09.2011    source источник
comment
Я думаю, что любой поток, в котором вы вызываете NSApplicationMain, становится основным потоком, в котором происходит цикл выполнения.   -  person spudwaffle    schedule 15.09.2011
comment
Это неправда. Я собрал простое приложение Cocoa, чтобы протестировать его. Приложение состоит из (1) основного метода, который вызывает Forker в новом потоке, (2) Forker, который вызывает NSApplicationMain, и (3) оконного контроллера, который получает управление после того, как NSApplicationMain сделал свое дело. Каждый из этих 3 печатает независимо от того, находится ли он в основном потоке, используя метод, упомянутый выше. Только (1) сообщает, что он находится в основном потоке, и приложение почти сразу вылетает. Он не падает, когда NSApplicationMain вызывается нормально.   -  person Calvin    schedule 15.09.2011
comment
Не беспокойся в таком случае. Ответ @matthias кажется хорошим.   -  person spudwaffle    schedule 16.09.2011


Ответы (1)


Здесь хорошее место для изучения NSApplicationMain, следуя повторной реализации функции. NSApplicationMain должен вызываться из основного потока в первую очередь потому, что

  1. Он обрабатывает основной интерфейс
  2. Элементы пользовательского интерфейса (в некоторых системах, а не только в OS X) должны вызываться в одном потоке для правильной работы.
  3. Графические элементы, предоставляемые инфраструктурой Cocoa, предполагают, что они будут работать в основном потоке.

Так что в значительной степени, поскольку Cocoa вызывает вещи в основном потоке, а пользовательский интерфейс должен выполняться в одном потоке, вам нужно работать в основном потоке для всего, что касается пользовательского интерфейса, включая NSApplicationMain.

person matthias    schedule 15.09.2011
comment
Это хорошая ссылка! Спасибо. Все это звучит правильно, но что делает основной поток таким особенным? Почему не какой-нибудь старый тред? Мне кажется, что пока я ограничиваю свое приложение одним потоком, не должно иметь значения, был ли этот поток первым. Есть ли какие-то системные вызовы, которые работают только из основного потока? (Если да, то почему?) Существуют ли какие-либо другие библиотеки, которые Cocoa может использовать с этим ограничением? Я родом из Java, где все потоки созданы равными, если вы правильно синхронизируете. - person Calvin; 16.09.2011
comment
Из того, что я узнал из документации Cocoa, просто Cocoa предполагает его в основном потоке и, следовательно, вероятно, специально размещает свои графические функции в основном потоке. Я думаю, что по крайней мере некоторые графические системы Unix не имеют этого ограничения (я видел обсуждения Qt, где графика работает в дочернем потоке), так что, вероятно, это Cocoa или одна из его зависимостей. - person matthias; 16.09.2011
comment
Из того, что я read, кажется, что многие платформы даже не имеют хорошего способа определить основной поток. Поэтому я полагаю, что окончательный ответ таков: варианты BSD могут идентифицировать основной поток, и Apple приняла решение сделать этот поток специальным для Cocoa. Мое лучшее предположение, почему это помогает обеспечить соблюдение ограничений на многопоточность. Я думаю, мы просто должны жить с этим. Спасибо за помощь, Матиас! - person Calvin; 18.09.2011
comment
@Calvin - определить основной поток на самом деле тривиально; основной поток — это просто другое название первого потока в программе, в котором выполняются _main и main. (Все программы начинаются как однопоточные и порождают новые потоки только в ответ на то, что происходит в main или его вызываемых объектах.) Таким образом, подпрограмма Apple _main может просто пометить текущий поток как основной поток, и это будет правильно. Тот факт, что некоторые платформы не предоставляют эту информацию пользователю, не означает, что у них нет концепции основного потока на уровне реализации. У каждого есть первая нить. - person Quuxplusone; 21.05.2013
comment
Основной поток поддерживается реализацией pthreads. В OS X он предоставляет функцию pthread_main_np(). В различных фреймворках высокого уровня консультируются с pthreads, чтобы, например, сделать CFRunLoopGetMain() равным CFRunLoopGetCurrent() для основного потока. Первый поток, запрашивающий основной цикл выполнения, создает его и сохраняет в общей переменной, но только основной поток возвращает этот цикл выполнения из CFRunLoopGetCurrent(). И т. д. В результате попытка запустить NSApplicationMain() в другом потоке не сработает, потому что этот поток не будет выполнять основной цикл выполнения. - person Ken Thomases; 07.12.2013