3

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

loop:
  ; alternative to sleep...
  jmp loop

有什么东西可以让这个过程闲置吗?

4

5 回答 5

6

你不能两全其美。您可以消耗 CPU,也可以让它做其他事情。正如 Vlad Lazarenko 建议的那样,您可以使用rep; nop;(也称为)来节省电力并避免剥夺其他核心的资源。pause但是,如果您在没有将核心让给另一个进程的情况下进行循环,那么至少该虚拟核心不能做任何其他事情。

于 2013-02-01T22:08:42.267 回答
3

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

当 Win32 环境中没有 GUI 活动时,有几种方法可以使应用程序空闲。主要(记录在 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
于 2013-02-01T23:46:18.953 回答
2

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

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

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

于 2013-02-01T22:11:28.893 回答
2

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

如果没有环 0 访问,您将永远找不到任何 x86 操作码来进入“空闲”模式......您只能找到一些消耗较少功率的指令(无内存访问,无缓存访问,无 FPU 访问,低 ALU 使用率...... .)。

于 2014-02-11T23:08:35.423 回答
1

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

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

CPU 从用户模式切换到内核模式:它到底做了什么?它是如何实现这种转变的?

如何完全挂起处理器?

我在这里找到的 Linux 用户空间示例:

.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... */
于 2013-02-01T22:08:16.740 回答