没有睡眠的CPU空闲循环

时间:2013-02-01 22:05:31

标签: windows assembly

我正在学习WIN32 ASM,我想知道是否存在类似“空闲”无限循环的东西,它根本不消耗任何资源。基本上我需要一个正在运行的过程来进行实验,如下所示:

loop:
  ; alternative to sleep...
  jmp loop

有什么东西可能会使这个过程无效吗?

5 个答案:

答案 0 :(得分:4)

你无法双管齐下。您可以使用CPU,也可以让它执行其他操作。正如Vlad Lazarenko建议的那样,您可以节省电力并避免使用rep; nop;(也称为pause)剥夺其他资源核心。但是如果你循环而不让核心转向另一个进程,至少那个虚拟核心不能做任何事情。

答案 1 :(得分:2)

“消耗资源”是什么意思?

如果你只想要一个什么都不做的命令?如果是这样,nop会这样做,您甚至可以循环播放:rep; nop。但是,CPU实际上将忙于工作:执行“无操作”指令。

如果你想要一条会导致CPU本身停止运行的指令,那么你就有点运气了:虽然有办法做到这一点,但你不能从用户空间做到这一点。

答案 2 :(得分:1)

是的,有些架构支持固有空闲状态AKA halt

例如,在x86 hlt中,操作码0xf4。可能只能在特权模式下调用。

CPU Switches from User mode to Kernel Mode : What exactly does it do? How does it makes this transition?

How to completely suspend the processor?

Linux的用户空间示例我发现here

.section .rodata
greeting:
.string "Hello World\n"
.text
_start:
mov $12,%edx /* write(1, "Hello World\n", 12) */
mov $greeting,%ecx
mov $1,%ebx
mov $4,%eax /* write is syscall 4 */
int $0x80
xorl %ebx, %ebx /* Set exit status and exit */
mov $0xfc,%eax
int $0x80
hlt /* Just in case... */

答案 3 :(得分:1)

注意:永远不要使用空循环来使应用程序空闲。它会将您的处理器加载到100%

当Win32环境中没有GUI活动时,有几种方法可以使应用程序空闲。 main(在MSDN中记录)是在主循环中使用“GetMessage”函数,以便从消息队列中提取消息。 当消息队列为空时,此函数将空闲,消耗非常低的处理器时间,等待消息到达消息队列。

下面是一个使用FASM宏库的示例:

msg_loop:
      invoke  GetMessage, msg, NULL, 0, 0
      cmp     eax, 1
      jb      end_loop
      jne     msg_loop
      invoke  TranslateMessage, msg
      invoke  DispatchMessage, msg
      jmp     msg_loop

当您希望捕获应用程序进入空闲状态并进行一些低优先级的一次性处理时(例如,根据应用程序的状态启用/禁用工具栏上的按钮),可以使用另一种方法)。

在这种情况下,必须使用PeekMessage和WaitMessage的组合。即使消息队列为空,PeekMessage函数也会立即返回。这样,您可以检测到这种情况并提供一些空闲任务,然后您必须调用WaitMessage以使进程空闲等待传入消息。

以下是我的代码(使用FreshLib宏)的简化示例:

; Main message loop
Run:
        invoke  PeekMessageA, msg, 0, 0, 0, PM_REMOVE
        test    eax,eax
        jz      .empty

        cmp     [msg.message], WM_QUIT
        je      .terminate

        invoke  TranslateMessage, msg
        invoke  DispatchMessageA, msg
        jmp     Run

.empty:
        call    OnIdle
        invoke  WaitMessage
        jmp     Run

.terminate:
        FinalizeAll
        stdcall TerminateAll, 0

答案 4 :(得分:1)

使用ring 0访问级别(如内核驱动程序),您可以使用x86 HLT操作码,但您需要具备系统编程技能才能真正了解如何使用它。使用HLT这种方式需要启用中断(未屏蔽)并保证发生中断(例如系统定时器),因为中断返回将执行HLT之后的下一条指令。

没有响铃0访问,你永远不会发现任何x86操作码进入“空闲”模式...... 您只能找到一些功耗更低的指令(无内存访问,无缓存访问,无FPU访问,ALU使用率低......)。