我正在尝试更好地理解运行循环,因为它们适用于Mac应用程序(NSRunLoop),但这也可能是一个更普遍的问题。 NSRunLoop文档说:
...您的代码提供了驱动运行循环的
while
或for
循环。在循环中,使用运行循环对象来“运行”接收事件的事件处理代码并调用已安装的处理程序。
文档的代码示例如下:
BOOL shouldKeepRunning = YES;
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
因此代码一直在调用run循环,直到它决定它应该终止。 -runMode:beforeDate:
方法“运行一次循环,阻止指定模式下的输入直到给定日期。”并且还有一个-run
方法,“将接收器置于永久循环中,在此期间它处理来自所有连接输入源的数据。”
如何重复调用run循环(或者调用-run
,听起来像这样做本身)不会消耗CPU? Cocoa应用程序在其主运行循环运行时可以在后台闲置,并且它将消耗零(或接近零)CPU时间。
在-runMode:beforeDate:
内,运行循环如何阻止输入接收或定时器在没有轮询和消耗CPU的情况下触发?
答案 0 :(得分:1)
这是一个很好的借口,可以进入一些Mac OS X内部!幸运的是,Core Foundation的相关部分是开源的。
通常的答案是“程序如何在不占用CPU的情况下等待 X ”?是“内核做到了”。在这种情况下,运行run循环实际上只是告诉内核你在等什么,然后让内核上下文切换掉。在这种情况下,运行循环将大部分时间花费在mach_msg
中,标志为MACH_RCV_MSG
,这实际上只是对内核的系统调用,最终调度其他一些线程运行。最终,会发生一些有趣的事情,这意味着Mach消息被发送到Mach端口,内核唤醒被阻塞的线程并传递消息。程序将此视为返回的mach_msg
函数。
有各种各样的方法来获取发送给您的马赫信息。例如,如果你设置一个NSTimer
,那么它可能会向下发送到mk_timer_arm
系统调用,这只会导致Mach消息在一定时间后被发送到某个地方。然后,运行循环不是一个奇特的无限循环,因为它是一个调度程序和内核与Cocoa(或Core Foundation)框架之间的映射。
不言而喻,如果内核由于您正在等待消息而暂停了您的线程,那么您实际上并没有使用任何CPU时间,这就是您的应用程序似乎处于空闲状态的原因。当你有一个现代内核时,为什么还要为无限循环而烦恼?