首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 函數級延遲實作方案:從秒級到時鐘週期的四種精度層次完整對比

     編輯:關於VC++

前言:為什麼不直接用 Sleep()?

Sleep() 會釋放 CPU 但阻塞訊息迴路,導致介面凍結、無法處理重繪/使用者輸入。本文整理四種「可處理訊息」的延遲方案,依精度由低至高:

方案一:秒級以上 — COleDateTime + 訊息泵 (來源:CSDN laiyiling)

#include  // 或 afx.h

COleDateTime start = COleDateTime::GetCurrentTime();
COleDateTimeSpan elapsed;

while (elapsed.GetTotalSeconds() <= 2.0) { // 延遲 2 秒
    MSG msg;
    if (::GetMessage(&msg, NULL, 0, 0)) {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    elapsed = COleDateTime::GetCurrentTime() - start;
}

優點:支援分鐘/小時/天 (GetTotalMinutes 等)、完整訊息處理。
缺點:精度約 1 秒,COleDateTime 較重。

方案二:毫秒級 — GetTickCount + 訊息泵 (來源:CSDN QunKangLi)

DWORD start = GetTickCount();
DWORD elapsed = 0;

while (elapsed <= 2000) { // 2000 ms = 2 秒
    MSG msg;
    if (::GetMessage(&msg, NULL, 0, 0)) {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    elapsed = GetTickCount() - start;
}

優點:輕量、~1ms 精度、標準 API。
注意:GetTickCount 49.7 天溢位,長延遲需處理。

方案三:微秒級 — QueryPerformanceCounter (高效能計數器,來源:CSDN tyzyx)

LARGE_INTEGER freq, start, now;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);

double target_us = 40.0; // 40 微秒
double elapsed_us = 0;

while (elapsed_us < target_us) {
    QueryPerformanceCounter(&now);
    elapsed_us = (double)(now.QuadPart - start.QuadPart) * 1e6 / freq.QuadPart;
    // 如需處理訊息,在此加入 GetMessage/Translate/Dispatch
}

優點:硬體級精度、跨處理器一致。
缺點:忙碌等待佔用 CPU、需自行加入訊息泵。

方案四:時鐘週期級 — 内嵌組語 NOP 迴圈

#define NOP_COUNT 3 // 需依 CPU 指令週期自行校準

__asm {
    mov ecx, NOP_COUNT
DELAY:
    nop
    loop DELAY
}

適用場景:硬體時序控制、極短延遲 (納秒級)。
警告:強烈不建議在應用層使用,受 CPU 主頻、超執行緒、電源管理影響極大,不可移植。

綜合比較表

方案精度訊息處理CPU 佔用適用場景
COleDateTime~1 秒完整低長延遲、背景任務輪詢
GetTickCount~1 ms完整低UI 延遲、動畫幀率控制
QueryPerformanceCounter~0.1 μs需手動加入高 (忙碌等待)高精度計時、效能分析
組語 NOP~1 ns無100%驅動程式、硬體協定

最佳實踐建議

  1. UI 相關延遲:優先 SetTimer/WM_TIMER,非阻塞、系統調度
  2. 需精確等待且處理訊息:GetTickCount + MsgWaitForMultipleObjects (可等待多物件)
  3. 高精度計時:QueryPerformanceCounter 僅用於測量,不用於延遲
  4. 避免忙碌等待:除非極短硬體時序,否則浪費電力與 CPU

進階:可取消的延遲等待類別封裝

class CDelayWait {
    DWORD m_start, m_timeout;
    bool m_cancelled;
public:
    CDelayWait(DWORD timeout_ms) : m_start(GetTickCount()), m_timeout(timeout_ms), m_cancelled(false) {}
    void Cancel() { m_cancelled = true; }
    bool Wait() {
        while (!m_cancelled && (GetTickCount() - m_start) < m_timeout) {
            MSG msg;
            if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
                if (msg.message == WM_QUIT) return false;
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            } else {
                ::Sleep(1); // 釋放 CPU 切片
            }
        }
        return !m_cancelled;
    }
};
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved