1

我试图更好地理解运行循环,因为它们适用于 Mac 应用程序(NSRunLoop),但这也可能是一个更普遍的问题。NSRunLoop 文档说:

...您的代码提供了驱动运行循环的whileorfor循环。在您的循环中,您使用运行循环对象来“运行”接收事件并调用已安装处理程序的事件处理代码。

文档有一个这样的代码示例:

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

所以代码一直调用运行循环,直到它决定它应该终止。方法“-runMode:beforeDate:运行一次循环,在指定的模式下阻塞输入,直到给定的日期。” 还有一种-run方法,“将接收器置于一个永久循环中,在此期间它处理来自所有附加输入源的数据”。

重复调用运行循环(或调用-run,听起来像,这本身)怎么可能不消耗 CPU?Cocoa 应用程序可以在其主运行循环运行时闲置在后台,它将消耗零(或接近零)的 CPU 时间。

在内部-runMode:beforeDate:,运行循环如何在没有轮询和消耗 CPU 的情况下阻塞直到接收到输入或计时器触发?

4

1 回答 1

2

这是探究一些 Mac OS X 内部结构的好借口!幸运的是,Core Foundation 的相关部分是开源的。

“程序如何在不占用 CPU的情况下等待X ?”的通常答案。是“内核做到了”。在这种情况下,运行运行循环实际上只是意味着告诉内核你在等待什么,然后让内核上下文切换离开。在这种情况下,运行循环将大部分时间花在mach_msgflag 上MACH_RCV_MSG,这实际上只是对内核的系统调用,最终会调度其他线程运行。最终,有趣的事情发生了,这意味着一条 Mach 消息被发送到一个 Mach 端口,内核唤醒被阻塞的线程并传递消息。程序将此视为mach_msg函数返回。

有各种底层方法可以将 Mach 消息发送给您。例如,如果您设置了一个NSTimer,它可能会一直运行到mk_timer_arm系统调用,这只会导致 Mach 消息在一定时间后发送到某个地方。因此,运行循环与其说是一个花哨的无限循环,不如说它是一个调度程序以及内核和 Cocoa(或 Core Foundation)框架之间的映射。

不用说,如果内核因为您正在等待消息而暂停了您的线程,那么您实际上并没有使用任何 CPU 时间,这就是您的应用程序似乎处于空闲状态的原因。当您拥有现代内核时,为什么还要为无限循环而烦恼?

于 2012-08-21T04:19:14.817 回答