```cpp #include #include #include #pragma comment( lib, "Winmm" ) static int counter = 0; static int64_t ticks_per_second; void __stdcall on_timer(HWN ...
#include <iostream>
#include <Windows.h>
#include <thread>
#pragma comment( lib, "Winmm" )
static int counter = 0;
static int64_t ticks_per_second;
void __stdcall on_timer(HWND h, UINT ui, UINT_PTR up, DWORD dw)
{
std::cout << "time out, counter=" << counter << std::endl;
counter = 0;
}
void get_message_trd_func()
{
SetTimer(NULL, 0, 1000, on_timer);
MSG msg;
while (GetMessageA(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
}
int main()
{
std::cout << "go!" << std::endl;
timeBeginPeriod(1);
QueryPerformanceFrequency((LARGE_INTEGER*)&ticks_per_second);
const double expected = 1.0 / 60.0;
const int64_t expected_ticks = (int64_t)(expected * ticks_per_second);
std::thread thr(get_message_trd_func);
for (;;)
{
int64_t before_ticks = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&before_ticks);
// do something...
for (int i = 0; i < 10000; i++)
{
float a = i * i + i + sin(i) + sqrt(i);
}
int64_t after_ticks = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&after_ticks);
counter++;
int64_t ticks_need_sleep = expected_ticks - (after_ticks - before_ticks);
double ms_need_sleep = (double)ticks_need_sleep / ticks_per_second * 1000.0;
if (ms_need_sleep >= 1.0)
Sleep((DWORD)ms_need_sleep);
else
continue;
}
}
這裡主要用到的幾個 win32api 為
-
MMRESULT timeBeginPeriod
使用該 api 需要鏈接Winmm
, 所以我們在文件頂部加入#pragma comment( lib, "Winmm" )
.
它的作用是請求提高一些計時器的精度比如這裡的Sleep
, 預設 windows 似乎只會給我們提供 10ms 左右很粗糙的精度, 所以這裡我們直接請求儘可能的高的精度, 即1ms
. -
QueryPerformanceFrequency
該 api 用於獲取"性能計時器"的精度, 單位是 ticks每秒. 在我的機子上它的值是10000000
, 可以看到精度還是很令人滿意的. 在這裡我們將其與expected
(也就是期望每次調用的間隔,單位s)進行相乘, 得到一個以ticks為單位的間隔. -
QueryPerformanceCounter
該 api 會檢測"性能計時器"的值, 單位為 ticks, 在 msdn 中其精度的描述為 <1us.
那麼結合上述幾個 api 以及幾個簡單的數學運算, 這樣就可以相對穩定的定時調用函數了(在這裡是 1s 60 次):
time out, counter=59
time out, counter=59
time out, counter=60
time out, counter=59
time out, counter=58
time out, counter=60
當你註釋掉timeBeginPeriod
的調用後你會發現結果不是很樂觀(即使我們期望 1s 調用 60 次):
time out, counter=33
time out, counter=31
time out, counter=32
time out, counter=31
最後, 這個可能常見於游戲的幀率控制, 實際上我就是從這裡知道的這些東西(x