Почему основной цикл выполнения приложения и обработка ввода не потребляют процессорное время? - PullRequest
1 голос
/ 13 марта 2012

Я пытаюсь лучше понять циклы выполнения применительно к приложениям Mac ( NSRunLoop ), но это также может быть более общий вопрос. Документация NSRunLoop гласит:

... ваш код обеспечивает цикл while или for, который управляет циклом выполнения. Внутри вашего цикла вы используете объект цикла выполнения для «запуска» кода обработки событий, который получает события и вызывает установленные обработчики.

Документы имеют пример кода, подобный следующему:

BOOL shouldKeepRunning = YES;
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

Таким образом, код продолжает вызывать цикл выполнения, пока не будет решено, что он должен завершиться. Метод -runMode:beforeDate: «Запускает цикл один раз, блокируя ввод в указанном режиме до указанной даты». И есть также метод -run, который «переводит приемник в постоянный цикл, в течение которого он обрабатывает данные из всех подключенных входных источников».

Как это возможно, что повторный вызов цикла выполнения (или вызов -run, который, похоже, сам по себе) не потребляет ЦП? Приложение Какао может бездействовать в фоновом режиме, пока выполняется его основной цикл выполнения, и оно будет использовать нулевое (или почти нулевое) время ЦП.

И в пределах -runMode:beforeDate:, как может блокировать цикл выполнения до получения ввода или срабатывания таймеров без опроса и загрузки ЦП?

1 Ответ

1 голос
/ 21 августа 2012

Это был хороший повод заглянуть внутрь некоторых Mac OS X! К счастью, соответствующие части Core Foundation имеют открытый исходный код.

Обычный ответ на вопрос "Как программа может ожидать X без загрузки процессора?" это «Ядро сделал это». В этом случае запуск цикла выполнения на самом деле означает просто сказать ядру, что вы ожидаете, а затем позволить контексту ядра переключиться. В этом случае цикл выполнения тратит большую часть своего времени в mach_msg с флагом MACH_RCV_MSG, который на самом деле является просто системным вызовом в ядре, что приводит к планированию запуска другого потока. В конце концов происходит что-то интересное, что означает, что сообщение Маха отправляется на порт Маха, и ядро ​​пробуждает заблокированный поток и доставляет сообщение. Программы воспринимают это как возвращение функции mach_msg.

Существуют все возможные способы получения сообщения Маха. Например, если вы установите NSTimer, это, вероятно, будет проходить вплоть до системного вызова mk_timer_arm, который просто заставляет сообщение Маха отправляться куда-то через определенное время. Таким образом, цикл выполнения - это не причудливый бесконечный цикл, а диспетчер и отображение между ядром и платформами Какао (или Базовой Основы).

Само собой разумеется, что если ядро ​​приостановило ваш поток, потому что вы ожидаете сообщения, то вы фактически не используете процессорное время, поэтому ваше приложение выглядит бездействующим. Зачем беспокоиться о бесконечном цикле, когда у вас современное ядро?

...