1. 程式人生 > >完美的Dos批處理實現sleep

完美的Dos批處理實現sleep

作者:tombkeeper[Base64Decode("dG9tYmtlZXBlckB4Zm9jdXMub3Jn")]
出處:http://hi.baidu.com/tombkeeper
時間:2007.03.23

我以前寫指令碼遇到需要Sleep的地方都是藉助於ping來實現,因為Windows的ping在發每個包之間都會呼叫KERNEL32!Sleep來掛起1秒鐘。最有意思的是在給Sleep傳遞引數的時候還會扣掉通訊往返所花的時間,所以非常精確。這部分反彙編出來是這樣的:

010020fe b8e8030000         mov        eax,3E8h       ;1000ms
01002103 8b7608             mov        esi,dword ptr [esi+8] ;取出icmp包往返所花的時間
01002106 3bf0               cmp        esi,eax     ;ping 127.0.0.1當然不會超過1000ms
01002108 7309               jae        ping+0x2113 (01002113)
0100210a 2bc6               sub        eax,esi ;減去通訊耗時
0100210c 50                 push       eax
0100210d ff1528100001       call       KERNEL32!Sleep

假設需要Sleep 10秒,就可以這樣寫:

SET SLEEP=ping 127.0.0.1 -n
%SLEEP% 11 > nul

不過前幾天我看到了更奇的辦法,不依賴任何外部命令,純用批處理實現Sleep,能精確到0.01秒,可惜已經無法考證出原始作者了。這是個2秒的例子:

@ECHO OFF
SETLOCAL EnableExtensions
CALL :ProcDelay 200
ECHO %TIME%
GOTO :EOF

:ProcDelay delayMSec_
SETLOCAL EnableExtensions
FOR /f "tokens=1-4 delims=:. " %%h IN ("%TIME%") DO SET start_=%%h%%i%%j%%k
     :_procwaitloop
     FOR /f "tokens=1-4 delims=:. " %%h IN ("%TIME%") DO SET now_=%%h%%i%%j%%k
     SET /a diff_=%now_%-%start_%
IF %diff_% LSS %1 GOTO _procwaitloop
ENDLOCAL & GOTO :EOF
:EOF