一、前言
因为接手的一个项目要做到精确到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的输出这里就不贴出了。有兴趣的可以自己测试一下,如果有问题,可以联系我,大家一起讨论和学习。