time(), clock(), gettimeofday()等庫函數需要2次查詢當前時間點,比較差值,才能判斷經過多少時間。也就是說如果需要在1S后觸發一個動作,就需要延時等待,而且要一直保持查詢,這樣就屬於阻塞方式了,會浪費大量CPU時間。
對於非阻塞方式,Linux下有alarm和setitime定時調用任務處理函數,可是Windows下要如何用非阻塞方式定時回調任務處理函數呢?
可以使用Windows API timeSetEvent(). 本文介紹如何在Win10x64專業版 + eclipse photon + CDT + MinGW環境下, 設置非阻塞方式的定時調用自定義任務處理函數,以達到周期性調用目的。
使用timeSetEvent 需要引入"WinMM.Lib"。
eclipse + CDT + MinGW C Linker引入方法:
1)檢查庫文件WinMM.Lib及路徑
檢查路徑下是否包含該lib文件,如果不包含需要重新下載,並放入推薦的默認路徑(路徑非必須按默認設置)。
文件默認路徑是
C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin\WinMM.Lib
推薦一個下載鏈接:
http://www.opdown.com/soft/125224.html
2)eclipse鏈接WiMM.lib庫
右鍵eclipse工程 屬性->C/C++ Build -> Settings -> MinGW C Linker -> Libraries,Library search path (-L)添加路徑,Libraries (-I) 添加文件(注意不要帶后綴名.lib,不然會報錯"ld.exe: cannot find -lWinMM.lib
3)工程代碼配置
工程中無需使用預編譯指令 #pragma comment (lib,"WinMM.Lib")。這點與VS平台不一樣。
4)代碼編寫
#include <windows.h> static int cnt = 0; void CALLBACK onTimeFunc(UINT wTimerID,UINT msg, DWORD dwUser,DWORD dw1,DWORD dw2) { cnt ++; time_t nowtime; time(&nowtime); char *p = ctime(&nowtime); printf("%s", p); fflush(stdout); // 強制刷新流 stream 的輸出緩沖區 } int main() { MMRESULT timer_id = timeSetEvent( 1000, // 以毫秒指定事件的周期 1, // 精度, 默認1ms &onTimeFunc, // 回調函數地址 (DWORD)1, // 存放用戶提供的回調數據 TIME_PERIODIC); // TIME_ONESHOT -- 執行一次; TIME_PERIODIC -- 周期性執行; if(!timer_id) { printf("timeSetEvent() failed with error %ld \n ", GetLastError()); return -1; } while(cnt < 10) { Sleep(100); // 睡眠, 精度1ms } timeKillEvent(timer_id); // 釋放定時器 return EXIT_SUCCESS; }
輸出
Sun Apr 26 16:24:54 2020 Sun Apr 26 16:24:55 2020 Sun Apr 26 16:24:56 2020 Sun Apr 26 16:24:57 2020 Sun Apr 26 16:24:58 2020 Sun Apr 26 16:24:59 2020 Sun Apr 26 16:25:00 2020 Sun Apr 26 16:25:01 2020 Sun Apr 26 16:25:02 2020 Sun Apr 26 16:25:03 2020
REF: