簡體   English   中英

Sleep(1) 和 SDL_Delay(1) 需要 15 ms

[英]Sleep(1) and SDL_Delay(1) takes 15 ms

我正在編寫一個 C++/SDL/OpenGL 應用程序,我遇到了最奇怪的錯誤。 使用簡單的可變時間步長,游戲似乎運行良好。 但隨后 FPS 開始表現異常。 我發現 Sleep(1) 和 SDL_Delay(1) 都需要 15 毫秒才能完成。

0-15 之間這些函數的任何輸入都需要 15 毫秒才能完成,將 FPS 鎖定在大約 64。如果我將其設置為 16,則需要 30 毫秒 OO

我的循環看起來像這樣:

while (1){
    GLuint t = SDL_GetTicks();
    Sleep(1); //or SDL_Delay(1)
    cout << SDL_GetTicks() - t << endl; //outputs 15
}

它很少會像預期的那樣需要 1 毫秒,但大部分時間需要 15 毫秒。

我的操作系統是 Windows 8.1。 CPU是英特爾i7。 我正在使用 SDL2。

自動收報機默認為 64 hz,或 15.625 ms/tick。 您需要使用 timeBeginPeriod(1) 將其更改為 1000hz == 1ms。 MSDN文章:

http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx

如果這里的目標是得到一個固定的頻率序列,你應該使用更高分辨率的定時器,但不幸的是這些只能被輪詢,所以需要輪詢和睡眠相結合來減少 cpu 開銷。 示例代碼,假設 Sleep(1) 可能需要近 2 毫秒(Windows XP 確實會發生這種情況,但 Windows 的更高版本不會發生這種情況)。

/* code for a thread to run at fixed frequency */
#define FREQ 400                        /* frequency */

typedef unsigned long long UI64;        /* unsigned 64 bit int */

LARGE_INTEGER liPerfFreq;               /* used for frequency */
LARGE_INTEGER liPerfTemp;               /* used for query */
UI64 uFreq = FREQ;                      /* process frequency */
UI64 uOrig;                             /* original tick */
UI64 uWait;                             /* tick rate / freq */
UI64 uRem = 0;                          /* tick rate % freq */
UI64 uPrev;                             /* previous tick based on original tick */
UI64 uDelta;                            /* current tick - previous */
UI64 u2ms;                              /* 2ms of ticks */
#if 0                                   /* for optional error check */
static DWORD dwLateStep = 0;
#endif
    /* get frequency */
    QueryPerformanceFrequency(&liPerfFreq);
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);

    /* wait for some event to start this thread code */
    timeBeginPeriod(1);                 /* set period to 1ms */
    Sleep(128);                         /* wait for it to stabilize */

    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
    uOrig = uPrev = liPerfTemp.QuadPart;

    while(1){
        /* update uWait and uRem based on uRem */
        uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
        uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
        /* wait for uWait ticks */
        while(1){
            QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
            uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
            if(uDelta >= uWait)
                break;
            if((uWait - uDelta) > u2ms)
                Sleep(1);
        }
        #if 0                    /* optional error check */
        if(uDelta >= (uWait*2))
            dwLateStep += 1;
        #endif
        uPrev += uWait;
        /* fixed frequency code goes here */
        /*  along with some type of break when done */
    }

    timeEndPeriod(1);                   /* restore period */

看起來 15 毫秒是操作系統將提供給您的最小切片。 我不確定您的具體框架,但 sleep 通常可以保證最短的睡眠時間。 (即它會休眠至少 1 毫秒。)

SDL_Delay()/Sleep() 在時間低於 10-15 毫秒時不能可靠地使用。 CPU 滴答的注冊速度不夠快,無法檢測到 1 毫秒的差異。

請參閱此處SDL 文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM