1. 程式人生 > >Windows下的高精度定時器實現及精確時刻獲取

Windows下的高精度定時器實現及精確時刻獲取

通訊、VOIP、視訊等領域的很多核心技術對時間精度的要求非常高,比如資料採集、時間同步、媒體流平滑控制、擁塞演算法等等,很多技術都是以毫秒為單位來進行計算和控制的。但是Windows設計之初並不是以實時系統為目標的,所以Windows系統的時間精度一直不高,實際最小單位是15ms左右,導致的結果就是所有Windows的時間、執行緒相關的操作都無法以1ms來實現精確控制。

受影響的操作包括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、高精度定時器

  1. #pragma once
  2. #include <Windows.h>
  3. #include <list>
  4. #include <akumaslab/system/singleton.hpp>
  5. namespace akumaslab{  
  6.     namespace time{  
  7.         using std::list;  
  8.         class PreciseTimerProvider  
  9.         {  
  10.             struct WaitedHandle{  
  11.                 HANDLE threadHandle;  
  12.                 LONGLONG elapsed;//超時時間
  13.             } ;  
  14.             typedef list< WaitedHandle > handle_list_type;  
  15.             typedef akumaslab::system::Singleton< PreciseTimerProvider > timer_type;  
  16.         public:  
  17.             PreciseTimerProvider(void):highResolutionAvailable(false), timerID(0)  
  18.             {  
  19.                 InitializeCriticalSection(&critical);  
  20.                 static LARGE_INTEGER systemFrequency;  
  21.                 if(0 != QueryPerformanceFrequency(&systemFrequency))  
  22.                 {  
  23.                     timeBeginPeriod(callbackInterval);  
  24.                     highResolutionAvailable = true;  
  25.                     countPerMilliSecond = systemFrequency.QuadPart/1000;  
  26.                     timerID = timeSetEvent(callbackInterval, 0, &PreciseTimerProvider::TimerFunc, NULL, TIME_PERIODIC);  
  27.                 }  
  28.             }  
  29.             //掛起當前執行緒
  30.             //@milliSecond:超時時間,單位:毫秒
  31.             bool suspendCurrentThread(int milliSecond)  
  32.             {  
  33.                 if(milliSecond <= 0)returnfalse;  
  34.                 if (!highResolutionAvailable)returnfalse;  
  35.                 HANDLE currentThreadHandle = GetCurrentThread();  
  36.                 HANDLE currentProcessHandle = GetCurrentProcess();  
  37.                 HANDLE realThreadHandle(0);  
  38.                 DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);  
  39.                 WaitedHandle item;  
  40.                 item.threadHandle = realThreadHandle;  
  41.                 LARGE_INTEGER now;  
  42.                 QueryPerformanceCounter(&now);  
  43.                 now.QuadPart += milliSecond * countPerMilliSecond;  
  44.                 item.elapsed = now.QuadPart;  
  45.                 EnterCriticalSection(&critical);  
  46.                 waitList.push_back(item);  
  47.                 LeaveCriticalSection(&critical);  
  48.                 //掛起執行緒
  49.                 SuspendThread(realThreadHandle);  
  50.                 CloseHandle(realThreadHandle);  
  51.                 returntrue;  
  52.             }  
  53.             //恢復超時執行緒
  54.             void resumeTimeoutThread()  
  55.             {  
  56.                 if (!highResolutionAvailable)return;  
  57.                 LARGE_INTEGER now;  
  58.                 QueryPerformanceCounter(&now);  
  59.                 EnterCriticalSection(&critical);  
  60.                 for (handle_list_type::iterator ir = waitList.begin(); ir != waitList.end(); )  
  61.                 {  
  62.                     WaitedHandle& waited = *ir;  
  63.                     if (now.QuadPart >= waited.elapsed)  
  64.                     {  
  65.                         ResumeThread(waited.threadHandle);  
  66.                         ir = waitList.erase(ir);  
  67.                         continue;  
  68.                     }  
  69.                     ir++;  
  70.                 }                                 
  71.                 LeaveCriticalSection(&critical);  
  72.             }  
  73.             ~PreciseTimerProvider(){  
  74.                 if (0 != timerID)  
  75.                 {  
  76.                     timeKillEvent(timerID);  
  77.                     timerID = 0;  
  78.                     timeEndPeriod(callbackInterval);  
  79.                 }  
  80.                 DeleteCriticalSection(&critical);  
  81.             }  
  82.         private:  
  83.             staticvoid CALLBACK TimerFunc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)  
  84.             {  
  85.                 staticbool initialed = false;  
  86.                 if (!initialed)  
  87.                 {  
  88.                     if (initialWorkThread())  
  89.                     {  
  90.                         initialed = true;  
  91.                     }  
  92.                     else{  
  93.                         return;  
  94.                     }  
  95.                 }  
  96.                 timer_type::getRef().resumeTimeoutThread();  
  97.             }  
  98.             //調整定時器工作執行緒優先順序
  99.             staticbool initialWorkThread()  
  100.             {  
  101.                 HANDLE realProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _getpid());  
  102.                 if (NULL == realProcessHandle)  
  103.                 {  
  104.                     returnfalse;  
  105.                 }  
  106.                 if (0 == SetPriorityClass(realProcessHandle, REALTIME_PRIORITY_CLASS))  
  107.                 {  
  108.                     CloseHandle(realProcessHandle);  
  109.                     returnfalse;  
  110.                 }  
  111.                 HANDLE currentThreadHandle = GetCurrentThread();  
  112.                 HANDLE currentProcessHandle = GetCurrentProcess();  
  113.                 HANDLE realThreadHandle(0);  
  114.                 DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);  
  115.                 SetThreadPriority(realThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);  
  116.                 //必須關閉複製控制代碼
  117.                 CloseHandle(realThreadHandle);  
  118.                 CloseHandle(realProcessHandle);  
  119.                 returntrue;  
  120.             }  
  121.         private:  
  122.             conststaticint callbackInterval = 1;  
  123.             CRITICAL_SECTION critical;  
  124.             MMRESULT timerID;  
  125.             LONGLONG countPerMilliSecond;  
  126.             bool highResolutionAvailable;  
  127.             handle_list_type waitList;  
  128.         };  
  129.         class PreciseTimer  
  130.         {  
  131.             typedef akumaslab::system::Singleton< PreciseTimerProvider > timer_type;  
  132.         public:  
  133.             staticbool wait(int milliSecond)  
  134.             {  
  135.                 //static PreciseTimerProvider timer;
  136.                 return timer_type::getRef().suspendCurrentThread(milliSecond);  
  137.             }  
  138.         };  
  139.     }  
  140. }  
 

DEMO

  1. int interval = 1;  
  2. int repeatCount = 50;  
  3. cout << getCurrentTime() << "test begin" << endl;  
  4. unit.reset();  
  5. for (int i = 0; i < repeatCount; i++)  
  6. {  
  7.     akumaslab::time::PreciseTimer::wait(interval);  
  8.     cout << getCurrentTime() << "/" << getNewTime() << " used " << unit.getPreciseElapsedTime() << " ms" << endl;  
  9.     unit.reset();  
  10. }  

2、精確時刻獲取

  1. #pragma once
  2. #include <sys/timeb.h>
  3. #include <time.h>
  4. #include <Windows.h>
  5. #include <akumaslab/system/singleton.hpp>
  6. namespace akumaslab{  
  7.     namespace time{  
  8.         struct HighResolutionTime  
  9.         {  
  10.             int year;  
  11.             int month;  
  12.             int day;  
  13.             int hour;  
  14.             int min;  
  15.             int second;  
  16.             int millisecond;  
  17.         };  
  18.         class CurrentTimeProvider  
  19.         {  
  20.         public:  
  21.             CurrentTimeProvider():highResolutionAvailable(false), countPerMilliSecond(0), beginCount(0)  
  22.             {  
  23.                 static LARGE_INTEGER systemFrequency;  
  24.                 if(0 != QueryPerformanceFrequency(&systemFrequency))  
  25.                 {  
  26.                     highResolutionAvailable = true;  
  27.                     countPerMilliSecond = systemFrequency.QuadPart/1000;  
  28.                     _timeb tb;  
  29.                     _ftime_s(&tb);  
  30.                     unsigned short currentMilli = tb.millitm;  
  31.                     LARGE_INTEGER now;  
  32.                     QueryPerformanceCounter(&now);  
  33.                     beginCount = now.QuadPart - (currentMilli*countPerMilliSecond);  
  34.                 }  
  35.             };  
  36.             bool getCurrentTime(HighResolutionTime& _time)  
  37.             {  
  38.                 time_t tt;  
  39.                 ::time(&tt);  
  40.                 tm now;  
  41.                 localtime_s(&now, &tt);  
  42.                 _time.year = now.tm_year + 1900;  
  43.                 _time.month = now.tm_mon + 1;  
  44.                 _time.day = now.tm_mday + 1;  
  45.                 _time.hour = now.tm_hour;  
  46.                 _time.min = now.tm_min;  
  47.                 _time.second = now.tm_sec;  
  48.                 if (!highResolutionAvailable)  
  49.                 {  
  50.                     _time.millisecond = 0;  
  51.                 }  
  52.                 else{  
  53.                     LARGE_INTEGER qfc;  
  54.                     QueryPerformanceCounter(&qfc);  
  55.                     _time.millisecond = (int)((qfc.QuadPart - beginCount)/countPerMilliSecond)%1000;  
  56.                 }  
  57.                 returntrue;  
  58.             }  
  59.         private:  
  60.             bool highResolutionAvailable;  
  61.             LONGLONG countPerMilliSecond;  
  62.             LONGLONG beginCount;  
  63.         };  
  64.         class CurrentTime  
  65.         {  
  66.         public:  
  67.             staticbool get(HighResolutionTime& _time)  
  68.             {  
  69.                 return akumaslab::system::Singleton< CurrentTimeProvider >::getRef().getCurrentTime(_time);  
  70.             }  
  71.         };  
  72.     }  
  73. }  

DEMO:

  1. HighResolutionTime time;  
  2. CurrentTime::get(time);  
  3. constint size = 20;  
  4. char buf[size] = {0};  
  5. _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

使用者定時SetTimerWindows訊息的傳遞處理

#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

windowsdig 域名解析工具安裝使用

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進行對比。在我看來,應當是各具優勢吧,雖然應用場景基本類似,但總會根據項目的不同來進行不通的選用。