Windows下的高精度定時器實現及精確時刻獲取
受影響的操作包括Sleep、GetTickCount、_ftime等等。比如你呼叫Sleep(2),期待2ms之後執行緒自動喚醒,但是實際結果可能是15ms甚至2x ms的時候才會喚醒,對於簡單應用來說影響不大,但是對於精度要求非常高的系統來說,這樣的問題就是非常致命的了。
程式碼思路如下:
1、高精度定時器。使用Singleton模式掛起請求Sleep的執行緒並統一管理,後臺使用Windows MultiMedia SDK的定期回撥函式不斷檢測並回復到時的執行緒,超時時間與當前時間採用QueryPerformanceCounter/QueryPerformanceFrequency的高精度計時,確保整體功能可靠性。
2、精確時刻獲取。由於可以獲取到毫秒級別的_ftime與GetTickCount都受到Windows系統時間精度影響,最小單位只有15ms,所以需要藉助QueryPerformanceCounter/QueryPerformanceFrequency進行準確計時。程式碼首先根據_ftime獲取起始時刻的精確刻度,然後根據差量計算當前的精確時刻。
程式碼中的Singleton模式可以找到很多實現,因此本文不進行詳述
程式碼(VS2005 c++編譯)
1、高精度定時器
- #pragma once
- #include <Windows.h>
- #include <list>
- #include <akumaslab/system/singleton.hpp>
- namespace akumaslab{
- namespace time{
- using std::list;
- class PreciseTimerProvider
- {
- struct WaitedHandle{
- HANDLE threadHandle;
- LONGLONG elapsed;//超時時間
- } ;
- typedef list< WaitedHandle > handle_list_type;
- typedef akumaslab::system::Singleton< PreciseTimerProvider > timer_type;
- public:
- PreciseTimerProvider(void):highResolutionAvailable(false), timerID(0)
- {
- InitializeCriticalSection(&critical);
- static LARGE_INTEGER systemFrequency;
- if(0 != QueryPerformanceFrequency(&systemFrequency))
- {
- timeBeginPeriod(callbackInterval);
- highResolutionAvailable = true;
- countPerMilliSecond = systemFrequency.QuadPart/1000;
- timerID = timeSetEvent(callbackInterval, 0, &PreciseTimerProvider::TimerFunc, NULL, TIME_PERIODIC);
- }
- }
- //掛起當前執行緒
- //@milliSecond:超時時間,單位:毫秒
- bool suspendCurrentThread(int milliSecond)
- {
- if(milliSecond <= 0)returnfalse;
- if (!highResolutionAvailable)returnfalse;
- HANDLE currentThreadHandle = GetCurrentThread();
- HANDLE currentProcessHandle = GetCurrentProcess();
- HANDLE realThreadHandle(0);
- DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
- WaitedHandle item;
- item.threadHandle = realThreadHandle;
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- now.QuadPart += milliSecond * countPerMilliSecond;
- item.elapsed = now.QuadPart;
- EnterCriticalSection(&critical);
- waitList.push_back(item);
- LeaveCriticalSection(&critical);
- //掛起執行緒
- SuspendThread(realThreadHandle);
- CloseHandle(realThreadHandle);
- returntrue;
- }
- //恢復超時執行緒
- void resumeTimeoutThread()
- {
- if (!highResolutionAvailable)return;
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- EnterCriticalSection(&critical);
- for (handle_list_type::iterator ir = waitList.begin(); ir != waitList.end(); )
- {
- WaitedHandle& waited = *ir;
- if (now.QuadPart >= waited.elapsed)
- {
- ResumeThread(waited.threadHandle);
- ir = waitList.erase(ir);
- continue;
- }
- ir++;
- }
- LeaveCriticalSection(&critical);
- }
- ~PreciseTimerProvider(){
- if (0 != timerID)
- {
- timeKillEvent(timerID);
- timerID = 0;
- timeEndPeriod(callbackInterval);
- }
- DeleteCriticalSection(&critical);
- }
- private:
- staticvoid CALLBACK TimerFunc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
- {
- staticbool initialed = false;
- if (!initialed)
- {
- if (initialWorkThread())
- {
- initialed = true;
- }
- else{
- return;
- }
- }
- timer_type::getRef().resumeTimeoutThread();
- }
- //調整定時器工作執行緒優先順序
- staticbool initialWorkThread()
- {
- HANDLE realProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _getpid());
- if (NULL == realProcessHandle)
- {
- returnfalse;
- }
- if (0 == SetPriorityClass(realProcessHandle, REALTIME_PRIORITY_CLASS))
- {
- CloseHandle(realProcessHandle);
- returnfalse;
- }
- HANDLE currentThreadHandle = GetCurrentThread();
- HANDLE currentProcessHandle = GetCurrentProcess();
- HANDLE realThreadHandle(0);
- DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
- SetThreadPriority(realThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
- //必須關閉複製控制代碼
- CloseHandle(realThreadHandle);
- CloseHandle(realProcessHandle);
- returntrue;
- }
- private:
- conststaticint callbackInterval = 1;
- CRITICAL_SECTION critical;
- MMRESULT timerID;
- LONGLONG countPerMilliSecond;
- bool highResolutionAvailable;
- handle_list_type waitList;
- };
- class PreciseTimer
- {
- typedef akumaslab::system::Singleton< PreciseTimerProvider > timer_type;
- public:
- staticbool wait(int milliSecond)
- {
- //static PreciseTimerProvider timer;
- return timer_type::getRef().suspendCurrentThread(milliSecond);
- }
- };
- }
- }
DEMO
- int interval = 1;
- int repeatCount = 50;
- cout << getCurrentTime() << "test begin" << endl;
- unit.reset();
- for (int i = 0; i < repeatCount; i++)
- {
- akumaslab::time::PreciseTimer::wait(interval);
- cout << getCurrentTime() << "/" << getNewTime() << " used " << unit.getPreciseElapsedTime() << " ms" << endl;
- unit.reset();
- }
2、精確時刻獲取
- #pragma once
- #include <sys/timeb.h>
- #include <time.h>
- #include <Windows.h>
- #include <akumaslab/system/singleton.hpp>
- namespace akumaslab{
- namespace time{
- struct HighResolutionTime
- {
- int year;
- int month;
- int day;
- int hour;
- int min;
- int second;
- int millisecond;
- };
- class CurrentTimeProvider
- {
- public:
- CurrentTimeProvider():highResolutionAvailable(false), countPerMilliSecond(0), beginCount(0)
- {
- static LARGE_INTEGER systemFrequency;
- if(0 != QueryPerformanceFrequency(&systemFrequency))
- {
- highResolutionAvailable = true;
- countPerMilliSecond = systemFrequency.QuadPart/1000;
- _timeb tb;
- _ftime_s(&tb);
- unsigned short currentMilli = tb.millitm;
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- beginCount = now.QuadPart - (currentMilli*countPerMilliSecond);
- }
- };
- bool getCurrentTime(HighResolutionTime& _time)
- {
- time_t tt;
- ::time(&tt);
- tm now;
- localtime_s(&now, &tt);
- _time.year = now.tm_year + 1900;
- _time.month = now.tm_mon + 1;
- _time.day = now.tm_mday + 1;
- _time.hour = now.tm_hour;
- _time.min = now.tm_min;
- _time.second = now.tm_sec;
- if (!highResolutionAvailable)
- {
- _time.millisecond = 0;
- }
- else{
- LARGE_INTEGER qfc;
- QueryPerformanceCounter(&qfc);
- _time.millisecond = (int)((qfc.QuadPart - beginCount)/countPerMilliSecond)%1000;
- }
- returntrue;
- }
- private:
- bool highResolutionAvailable;
- LONGLONG countPerMilliSecond;
- LONGLONG beginCount;
- };
- class CurrentTime
- {
- public:
- staticbool get(HighResolutionTime& _time)
- {
- return akumaslab::system::Singleton< CurrentTimeProvider >::getRef().getCurrentTime(_time);
- }
- };
- }
- }
DEMO:
- HighResolutionTime time;
- CurrentTime::get(time);
- constint size = 20;
- char buf[size] = {0};
- _snprintf_s(buf, size, size, "%02d:%02d %02d:%02d:%02d.%03d ", time.month, time.day, time.hour, time.min, time.second, time.millisecond);
測試結果如下,下圖是高精度計時器按1ms進行Sleep的結果,左側為使用_ftime計時,右側為使用精確時刻計時,總體來說,雖然無法達到100%可靠,但是相對原來的15ms已經有較大提升,期望Windows能夠儘快提供真正的高精度時間管理技術
相關推薦
Windows下的高精度定時器實現及精確時刻獲取
通訊、VOIP、視訊等領域的很多核心技術對時間精度的要求非常高,比如資料採集、時間同步、媒體流平滑控制、擁塞演算法等等,很多技術都是以毫秒為單位來進行計算和控制的。但是Windows設計之初並不是以實時系統為目標的,所以Windows系統的時間精度一直不高,實際最小單位是1
windows平臺下的高精度定時器
class CHTimerListener { public: virtual void Update() = 0; }; class CHTimer { public: CHTime
Linux時間子系統之六:高精度定時器(HRTIMER)的原理和實現
3.4 size 屬於 running return repr 而是 復雜度 ctu 上一篇文章,我介紹了傳統的低分辨率定時器的實現原理。而隨著內核的不斷演進,大牛們已經對這種低分辨率定時器的精度不再滿足,而且,硬件也在不斷地發展,系統中的定時器硬件的精度也越來越高,這也給
C#實現高精度定時器
轉自https://blog.csdn.net/nocky/article/details/6056413 這兩天正在準備做一個實時控制的東西,想用C#。可是昨天日本人展示了一個在LINUX平臺下使用C語言控制的單自由度機械臂,我問他們為什麼不用WINDOWS,他們說用WIND
Windows下的多媒體定時器:timeSetEvent 使用方法及易出錯的幾種情況
MMRESULT timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent ) &
VC++ 下多媒體高精度定時器timeSetEvent
設定timer事件物件; uDelay 是定時器間隔; uResolution 是解析度,即定時器的精度,為0表示儘可能最大; lpTimeProc是定時器回撥; dwUser 是回撥引數; fuEvent 是定時器的屬性: TIME_ONESHOT 表示回撥執行一次 TIME_PERIOD
Linux 高精度定時器hrtimers簡單介紹和應用場景
hrtimer:high-resolution kernel timers: hrtimers的誕生是由於核心開發者在使用過程中發現,原始的定時器kernel/timers.c,已經可以滿足所有場景的,但是在實際的大量測試中發現還是無法滿足所有場景,所以hrtime
golang 高效低精度定時器實現
golang預設定時器是通過time模組提供的,不管是golang,libev,libevent也好,定時器都是通過最小堆實現的,導致加入定時器時間複雜度為O(lgn),在需要大量定時器時效率較低,所以Linux提供了基於時間輪的實現,我們本次提供的貼一張Linux時
hrtimer核心高精度定時器
#include <linux/kernel.h> #include <linux/module.h> #include <linux/hrtimer.h> #include <linux/ktime.h> MODULE_LI
Windows/Linux高精度計時器(C++)
/* * Linux/Windows 系統高精度計時器 */ #ifndef __LX_TIMER_H__ #define __LX_TIMER_H__ #ifdef WI
關於linux hrtimer高精度定時器的使用註意事項
linux設備驅動 mar 定時函數 src int 這樣的 vpd 由於 高精 關於linux hrtimer高精度定時器的使用註意事項 需要註意:由於hrtimer本身沒有interval周期的概念,如果要實現hrtimer的周期調用,方法1) 超時函數,調用hrtim
Windows高精度微秒級(併發)定時器實現
自從上次封裝微秒延時函式後,利用空閒時間試著封裝一個微秒定時器(類似MFC定時器形式)使用起來效果還不錯。 關於定時器的幾點介紹: 1.設計採用了自動釋放定時器節點方式(增加虛解構函式在內部做相關釋放判斷,即使用完不釋放節點也沒關係); 2
C++11 中chrono庫 實現高精度定時
一種“傳統”ctime計時方法: #include <ctime> using namespace std; clock_t start = clock(); // do something... clock_t end = clock(); cout <<
Visual C++實現微秒級精度定時器
在工業生產控制系統中,有許多需要定時完成的操作,如:定時顯示當前時間,定時重新整理螢幕上的進度條,上位機定時向下位機發送命令和傳送資料等。特別是在對控制性能要求較高的控制系統和資料採集系統中,就更需要精確定時操作。眾所周知,Windows是基於訊息機制的系統,任何事件的執行
windows下搭建syslog服務器及基本配置
3.4 set 去掉 一個 截圖 rate lock https pre 一、環境 windows7 64位+ kiwi_syslog_server_9.5.0 kiwi_syslog百度雲下載地址: 鏈接: https://pan.baidu.com/s/1Ep
使用者定時器SetTimer及Windows訊息的傳遞處理
#include <windows.h> #include <stdio.h> #include <conio.h> int coun
Go中定時器實現原理及原始碼解析
> 轉載請宣告出處哦~,本篇文章釋出於luozhiyun的部落格:https://www.luozhiyun.com > > 本文使用的go的原始碼15.7,需要注意的是由於timer是1.14版本進行改版,但是1.14和1.15版本的timer並無很大區別 我在春節期間寫了一篇文章有關時間輪的:https
linux 下高精度時間
定時器 精度 處理 turn 通過 公司 cti include processor 今天在公司代碼中看到了使用select函數的超時功能作定時器的用法,便整理了如下幾個Linux下的微秒級別的定時器。在我的Ubutu10.10 雙核環境中,編譯通過。 [cpp] vi
windows下dig 域名解析工具安裝及使用
dig 解析 windows 下nslookup 解析命令工具,都已經為人所熟悉。除此之外,在linux 或 unix上,dig命令工具在解析方面更是主導。下面主要說明下,dig如何在windows下安裝和使用dig 命令工具。dig的執行程序是在Bind軟件包裏,首先要下載Bind軟件,下載地址ht
Windows下搭建Redis服務器
targe 文件夾 cnblogs 成功 tps cache ase view tar Redis服務器是當下比較流行的緩存服務器,Redis通常被人拿來和Memcached進行對比。在我看來,應當是各具優勢吧,雖然應用場景基本類似,但總會根據項目的不同來進行不通的選用。