一、前言
因為接手的一個項目要做到精確到1ms以內的定時觸發功能,在測試過 Sleep(DWORD millsecond)函數的准確度之后,該函數不能滿足要求。上網查詢了相詢了相關資料,現將測試過程總結一下,方便自己以后翻閱。
二、測試過程
1.開發平台:系統windows 7 + vs2013 + win32
2.相關代碼
代碼1如下所示:

1 #include "stdafx.h" 2 #include <iostream> 3 #include <vector> 4 #include "math.h" 5 #include "windows.h" 6 #include "stdio.h" 7 8 using namespace std; 9 10 //是否調用Sleep()函數的閾值 11 #define VALUE_NO_SLEEP 8 12 13 14 15 /// 16 //函數功能:精確延時函數 17 //函數參數:延時時間 18 //返回值:實際延時時間 19 double MyDelay(double millsecond) 20 { 21 LARGE_INTEGER litmp; 22 LONGLONG qt1, qt2; 23 double dft, dff, dfm; 24 25 //獲得時鍾頻率 26 QueryPerformanceFrequency(&litmp);//獲得時鍾頻率 27 dff = (double)litmp.QuadPart; 28 29 //獲得初始值 30 QueryPerformanceCounter(&litmp); 31 qt1 = litmp.QuadPart; 32 33 double delayTime = 0; 34 if (millsecond > VALUE_NO_SLEEP) //10ms 的效果會比較好,效果好於5ms、6ms、8ms 35 { 36 Sleep(millsecond - VALUE_NO_SLEEP); 37 } 38 39 //程序延時 40 do 41 { 42 //除法運算用於耗時 43 double tmp = 1.0 / 3; 44 QueryPerformanceCounter(&litmp); 45 qt2 = litmp.QuadPart; 46 47 //獲得精確時間值,轉到毫秒單位上 48 dft = (double)(qt2 - qt1)/dff; 49 //dft = dfm / dff; 50 //printf("當前用時: %.3f 毫秒\n", dft*1000.0); 51 } while (dft * 1000 < millsecond); 52 //結束時用時 53 //printf("實際用時: %.3f 毫秒\n", dft*1000.0); 54 return dft*1000.0; 55 56 } 57 58 59 60 int _tmain(int argc, _TCHAR* argv[]) 61 { 62 63 64 double time = MyDelay(45); 65 printf("實際延時時間:%.3f\n", time); 66 67 68 //測試一: 69 //記錄時間 70 vector<double> record; 71 72 LARGE_INTEGER ts, te, tc; 73 double ds, de; 74 LONGLONG qts, qte; 75 //獲取時鍾頻率 76 QueryPerformanceFrequency(&tc); 77 ds = (double)tc.QuadPart; 78 79 for(int i=0;i<50;++i) 80 { 81 //獲取初始值 82 QueryPerformanceCounter(&ts); 83 qts = ts.QuadPart; 84 85 //做運算,用於耗時 86 double arr[20480] = {0.0}; 87 for(int i=0;i<20480;++i) 88 { 89 arr[i] = double(i+1)/3; 90 } 91 //精確獲取計算時間 92 QueryPerformanceCounter(&ts); 93 qte = ts.QuadPart; 94 95 //獲得精確時間值,轉到毫秒單位上 96 de = (double)(qte - qts) / ds; 97 //實際耗時 98 de *= 1000.0; 99 printf("除法運算耗時:%.3f毫秒\n", de); 100 record.push_back(de); 101 double tmp = MyDelay(50.0 - de); 102 printf("精確延時:%.3f毫秒\n",tmp); 103 record.push_back(tmp); 104 //實際共耗時 105 QueryPerformanceCounter(&ts); 106 qte = ts.QuadPart; 107 //獲得精確時間值,轉到毫秒單位上 108 de = (double)(qte - qts) / ds; 109 //實際耗時 110 de *= 1000.0; 111 printf("實際共耗時:%.3f毫秒\n\n",de); 112 record.push_back(de); 113 } 114 115 FILE* fp = fopen("record.txt", "a+"); 116 if(fp != NULL) 117 { 118 for(int i=0;i<record.size();++i) 119 { 120 char info[16] = {0}; 121 sprintf(info, "%.4f\n", record[i]); 122 fwrite(info,1,strlen(info), fp); 123 } 124 fclose(fp); 125 } 126 else 127 { 128 fclose(fp); 129 return -1; 130 } 131 132 system("pause"); 133 return 0; 134 }
代碼1的命令行輸出不滿足設計想法,輸出如下所示:

//單獨測試MyDelay(45)的輸出結果 實際延時時間:45.836 除法運算耗時:0.526毫秒 精確延時:49.474毫秒 實際共耗時:51.900毫秒 除法運算耗時:0.499毫秒 精確延時:49.501毫秒 實際共耗時:51.882毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:51.820毫秒 除法運算耗時:0.500毫秒 精確延時:49.500毫秒 實際共耗時:51.792毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:51.805毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:51.696毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.944毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:54.605毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.843毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.848毫秒 除法運算耗時:0.500毫秒 精確延時:49.500毫秒 實際共耗時:52.955毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.718毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.433毫秒 除法運算耗時:0.303毫秒 精確延時:49.698毫秒 實際共耗時:51.968毫秒 除法運算耗時:0.298毫秒 精確延時:49.702毫秒 實際共耗時:52.010毫秒 除法運算耗時:0.309毫秒 精確延時:49.691毫秒 實際共耗時:53.467毫秒 除法運算耗時:0.300毫秒 精確延時:49.700毫秒 實際共耗時:51.943毫秒 除法運算耗時:0.295毫秒 精確延時:49.705毫秒 實際共耗時:52.539毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.724毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.609毫秒 除法運算耗時:0.500毫秒 精確延時:49.500毫秒 實際共耗時:52.753毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.756毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.622毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.799毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.687毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.875毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.738毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.864毫秒 除法運算耗時:0.523毫秒 精確延時:49.477毫秒 實際共耗時:54.418毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.700毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:53.040毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.781毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:53.402毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:54.049毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.694毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.861毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.686毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.691毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.738毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.646毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:53.498毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.701毫秒 除法運算耗時:0.506毫秒 精確延時:49.495毫秒 實際共耗時:54.056毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.662毫秒 除法運算耗時:0.501毫秒 精確延時:49.499毫秒 實際共耗時:52.678毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.821毫秒 除法運算耗時:0.503毫秒 精確延時:49.497毫秒 實際共耗時:52.664毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.749毫秒 除法運算耗時:0.502毫秒 精確延時:49.498毫秒 實際共耗時:52.671毫秒 除法運算耗時:0.500毫秒 精確延時:49.500毫秒 實際共耗時:52.922毫秒
再次查看代碼時,產生疑惑:是不是多余的乘法運算和printf()輸出導致【實際共耗時】與【除法運算耗時】、【精確延時】的加和相差較大的現象。立即着手屏蔽這些代碼,並且只記錄每次for循環開始時刻的精確時間,代碼2如下所示:

1 #include "stdafx.h" 2 #include <iostream> 3 #include <vector> 4 #include "math.h" 5 #include "windows.h" 6 #include "stdio.h" 7 8 using namespace std; 9 10 11 #define VALUE_NO_SLEEP 8 12 13 14 15 /// 16 //函數功能:精確延時函數 17 //函數參數:延時時間 18 //返回值:實際延時時間 19 double MyDelay(double millsecond) 20 { 21 LARGE_INTEGER litmp; 22 LONGLONG qt1, qt2; 23 double dft, dff, dfm; 24 25 //獲得時鍾頻率 26 QueryPerformanceFrequency(&litmp);//獲得時鍾頻率 27 dff = (double)litmp.QuadPart; 28 29 //獲得初始值 30 QueryPerformanceCounter(&litmp); 31 qt1 = litmp.QuadPart; 32 33 double delayTime = 0; 34 if (millsecond > VALUE_NO_SLEEP) 35 { 36 Sleep(millsecond - VALUE_NO_SLEEP); 37 } 38 39 //程序延時 40 do 41 { 42 //除法運算用於耗時 43 double tmp = 1.0 / 3; 44 QueryPerformanceCounter(&litmp); 45 qt2 = litmp.QuadPart; 46 47 //獲得精確時間值,轉到毫秒單位上 48 dft = (double)(qt2 - qt1) / dff; 49 //dft = dfm / dff; 50 //printf("當前用時: %.3f 毫秒\n", dft*1000.0); 51 } while (dft * 1000 < millsecond); 52 //結束時用時 53 //printf("實際用時: %.3f 毫秒\n", dft*1000.0); 54 return dft*1000.0; 55 56 } 57 58 59 int _tmain(int argc, _TCHAR* argv[]) 60 { 61 62 //測試MyDelay函數 63 double time = MyDelay(45); 64 printf("實際延時時間:%.3f\n", time); 65 66 67 //測試二:不做冗余的計算和打印,只記錄循環開始的精確時間 68 //記錄時間 69 vector<LONGLONG> record2; 70 LARGE_INTEGER ts, te, tc; 71 double ds, de; 72 LONGLONG qts, qte; 73 //獲取時鍾頻率 74 QueryPerformanceFrequency(&tc); 75 ds = (double)tc.QuadPart; 76 //循環1000次,以便觀察,消除偶然性 77 for (int i = 0; i < 1000; ++i) 78 { 79 //獲取初始值 80 QueryPerformanceCounter(&ts); 81 qts = ts.QuadPart; 82 record2.push_back(qts); 83 //做運算 84 double arr[20480] = { 0.0 }; 85 for (int i = 0; i < 20480; ++i) 86 { 87 arr[i] = double(i + 1) / 3; 88 } 89 90 //除法運算實際耗時 91 QueryPerformanceCounter(&ts); 92 qte = ts.QuadPart; 93 //獲得精確時間值,轉到毫秒單位上 94 de = (double)(qte - qts) / ds * 1000.0; 95 //printf("除法運算耗時:%.3f毫秒\n", de); 96 double tmp = MyDelay(50.0 - de); 97 //去除多余的計算和查詢時間,每次只記錄循環開始的精確時間 98 } 99 100 FILE* fp = fopen("record.txt", "w+"); 101 char *data = new char[10240]; 102 memset(data, 0, sizeof(data)); 103 if (fp != NULL) 104 { 105 for (int i = 0; i < record2.size() - 1; ++i) 106 { 107 //輸出前后兩次記錄值之間的差值,即一次循環的耗時 108 de = (double)(record2[i + 1] - record2[i]) / ds * 1000.0; 109 char info[16] = { 0 }; 110 sprintf(info, "%.4f\n", de); 111 strcat(data, info); 112 } 113 fwrite(data, 1, strlen(data), fp); 114 fclose(fp); 115 delete[]data; 116 data = NULL; 117 } 118 else 119 { 120 fclose(fp); 121 return -1; 122 } 123 124 system("pause"); 125 return 0; 126 }
代碼2的輸出這里就不貼出了。有興趣的可以自己測試一下,如果有問題,可以聯系我,大家一起討論和學習。