私は現在 WIN32 ASM を学んでおり、リソースをまったく消費しない「アイドル」無限ループのようなものがあるかどうか疑問に思っていました。基本的に、次のような実験を行う実行中のプロセスが必要です。
loop:
; alternative to sleep...
jmp loop
プロセスをアイドル状態にする可能性のあるものはありますか?
両方の方法を持つことはできません。CPU を消費することも、別のことをさせることもできます。Vlad Lazarenko が提案したように、rep; nop;
(としても知られている)を使用すると、電力を節約し、他のコアのリソースを奪うことを回避できます。pause
しかし、コアを別のプロセスに渡さずにループすると、少なくともその仮想コアは他に何もできなくなります。
注:アプリケーションをアイドル状態にするために空のループを使用しないでください。プロセッサを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
アプリケーションがアイドル状態になる瞬間をキャッチし、優先度の低い 1 回限りの処理を行う場合 (たとえば、アプリケーションの状態に応じてツールバーのボタンを有効/無効にするなど) には、別のアプローチが使用されます。
この場合、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
「リソースを消費する」とはどういう意味ですか?
何もしないコマンドが必要な場合は?そうすればnop
、好きなだけループすることもできます: rep; nop
. ただし、CPU は実際には作業で忙しくなります。つまり、「操作なし」命令を実行します。
CPU自体を停止させる命令が必要な場合は、ちょっと運が悪いです.それを行う方法はありますが、ユーザー空間から行うことはできません.
はい、組み込みのアイドル状態 AKA をサポートするアーキテクチャがいくつかありますhalt
。
たとえば、 x86hlt
では opcode 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... */