首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

怎么做到精确延时

2013-01-28 
如何做到精确延时?本帖最后由 VisualEleven 于 2013-01-05 15:02:07 编辑由于系统要求做到0.01毫秒以上的

如何做到精确延时?
本帖最后由 VisualEleven 于 2013-01-05 15:02:07 编辑 由于系统要求做到0.01毫秒以上的精度延时,我使用QueryPerformanceCounter(), 大概代码如下:

LARGE_INTEGER Frequency;
LARGE_INTEGER StartTicks, CurrentTicks;

QueryPerformanceFrequency(&Frequency);

QueryPerformanceCounter(&StartTicks);

do
{
   //Sleep(1); 
   QueryPerformanceCounter(&CurrentTicks);
}while(CurrentTicks - StartTitcks > ...);

QueryPerformanceCounter()是可以获得精确计时, 但是延时如何做到呢? 
如果使用Sleep(), 那使用QueryPerformanceCounter()就没有任何意义了, 因为Sleep()精度连1ms都做不到.
如果不使用Sleep(), CPU占用100%, 也没有意义.
请问我该如何应用QueryPerformanceCounter? integer
[解决办法]
引用:
引用:内核延时都可以精确到微秒的吧,你可以通过内核的驱动程序去弄计时的地方

具体是怎么搞的?


0.05MS的精度我觉得是有的吧,你把你的sleep的调用改成驱动的通信就好,比如驱动里设置个EVENT,超时50US,然后你的应用程序等待这个EVENT就达到了延时的目的吧
[解决办法]
windows下有多种定时器,可尝试用定时器来延时,但可惜的是这些定时器时间分辨率都不太高,多是以milliseconds为单位,最大分辨率1milliseconds,若想更精确的,就得另想办法。
我的想法是,如果需要的分辨率为0.01milliseconds,则可以创建100个定时器,每个定时器间隔0.01milliseconds(可利用QueryPerformanceCounter),这样,100个定时器循环定时,大致就能做到0.01milliseconds的分辨率。但是注意,并不是每种定时器类型都可创建我们需要的个数。我写了测试代码,如下,供参考,代码都很简单,因此就没太多注释:

#define _WIN32_WINNT 0x0500 

#include <Windows.h>
#include <stdio.h>

#define ERASE_TIME_IN_MILLISEC(c, s, f)\
(((double)c.QuadPart - s.QuadPart) / f.QuadPart * 1000)

#define USE2
#define DELAY_TIME100// microseconds (0.001 milliseconds)
#define TIMMER_COUNT((1000 / DELAY_TIME) * 2)

LARGE_INTEGER g_lnFrequency = {0};
LARGE_INTEGER g_lnStartPerfmcCount= {0};
LARGE_INTEGER g_lnCurrPerfmcCount = {0};

HANDLE g_hEvent = NULL;

void CALLBACK TimerFunction(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
QueryPerformanceCounter(&g_lnCurrPerfmcCount);
printf("TimerID : %d  erase time : %lf\n", wTimerID,
ERASE_TIME_IN_MILLISEC(g_lnCurrPerfmcCount, g_lnStartPerfmcCount, g_lnFrequency));
g_lnStartPerfmcCount.QuadPart = g_lnCurrPerfmcCount.QuadPart;
}

void CALLBACK TimerProc(void* lpParametar,
BOOLEAN TimerOrWaitFired)
{
//int *p = (int *)lpParametar;
QueryPerformanceCounter(&g_lnCurrPerfmcCount);
// printf("ThreadID : %d  para : %4d  erase time : %lf\n", GetCurrentThreadId(), *p,
//    ERASE_TIME_IN_MILLISEC(g_lnCurrPerfmcCount, g_lnStartPerfmcCount, g_lnFrequency));
printf("erase time : %lf\n", 
ERASE_TIME_IN_MILLISEC(g_lnCurrPerfmcCount, g_lnStartPerfmcCount, g_lnFrequency));
g_lnStartPerfmcCount.QuadPart = g_lnCurrPerfmcCount.QuadPart;
}

int main(int, char **, char **)
{
QueryPerformanceFrequency(&g_lnFrequency);

g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

#if 1 == USE
LARGE_INTEGER lnFrequency = {0};
LARGE_INTEGER lnStartPerfmcCount= {0};


LARGE_INTEGER lnCurrPerfmcCount = {0};
lnFrequency.QuadPart = g_lnFrequency.QuadPart;

do 
{
QueryPerformanceCounter(&lnStartPerfmcCount);

// 这儿期望可以短暂延时,降低CPU使用率
WaitForSingleObject(g_hEvent, 0);

QueryPerformanceCounter(&lnCurrPerfmcCount);

printf("wait time : %lf milliseconds\n", 
ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency));
} while (TRUE);

#elif 2 == USE
LARGE_INTEGER lnFrequency = {0};
LARGE_INTEGER lnStartPerfmcCount = {0};
LARGE_INTEGER lnStartPerfmcCountTmp = {0};
LARGE_INTEGER lnFirstStartPerfmcCount = {0};
LARGE_INTEGER lnLastStartPerfmcCount = {0};
LARGE_INTEGER lnCurrPerfmcCount = {0};
lnFrequency.QuadPart = g_lnFrequency.QuadPart;

TIMECAPS tc;
    timeGetDevCaps(&tc, sizeof(TIMECAPS));
    UINT unResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
    timeBeginPeriod(unResolution);

// 首次创建定时器较耗时,因此单独先创建一个定时器,但不使用
timeKillEvent(
timeSetEvent(1, 0, (LPTIMECALLBACK)g_hEvent, NULL, TIME_ONESHOT 
[解决办法]
 TIME_CALLBACK_EVENT_SET));

MMRESULT mmrTimmer = NULL;
MMRESULT mmrTimmerTmp = NULL;

timeSetEvent(1, 0, (LPTIMECALLBACK)g_hEvent, NULL, TIME_PERIODIC 
[解决办法]
 TIME_CALLBACK_EVENT_SET);
QueryPerformanceCounter(&lnStartPerfmcCount);
lnFirstStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
do 
{
mmrTimmer = timeSetEvent(
1, 0, (LPTIMECALLBACK)g_hEvent, NULL, TIME_PERIODIC 
[解决办法]
 TIME_CALLBACK_EVENT_SET);

QueryPerformanceCounter(&lnCurrPerfmcCount);
Judge:
if (ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency) * 1000 < DELAY_TIME)
{
if (NULL != mmrTimmerTmp)
{
timeKillEvent(mmrTimmerTmp);
}

mmrTimmerTmp = mmrTimmer;
lnStartPerfmcCountTmp.QuadPart = lnCurrPerfmcCount.QuadPart;
}
else
{
if (NULL != mmrTimmerTmp)
{
mmrTimmerTmp = NULL;
lnStartPerfmcCount.QuadPart = lnStartPerfmcCountTmp.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
goto Judge;
}
else
{
lnStartPerfmcCount.QuadPart = lnCurrPerfmcCount.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
}
}
} while (ERASE_TIME_IN_MILLISEC(lnLastStartPerfmcCount, lnFirstStartPerfmcCount, lnFrequency) <= 1.0);

if (NULL != mmrTimmerTmp)
{
timeKillEvent(mmrTimmerTmp);
mmrTimmerTmp = NULL;
}

do 
{
QueryPerformanceCounter(&lnStartPerfmcCount);

WaitForSingleObject(g_hEvent, INFINITE);

QueryPerformanceCounter(&lnCurrPerfmcCount);

printf("wait time : %lf milliseconds\n",


ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency));
} while (TRUE);

#elif 3 == USE
int nTimmerExist[TIMMER_COUNT] = {0};
int nTimmerLength = DELAY_TIME / 2;
int nTimmerCount = 0;

LARGE_INTEGER lnFrequency = {0};
LARGE_INTEGER lnStartPerfmcCount = {0};
LARGE_INTEGER lnFirstStartPerfmcCount = {0};
LARGE_INTEGER lnCurrPerfmcCount = {0};
lnFrequency.QuadPart = g_lnFrequency.QuadPart;

int nIndex = 0;
MMRESULT mmrTimmer = NULL;
do 
{
// mmrTimmer = timeSetEvent(
// 1, 0, (LPTIMECALLBACK)g_hEvent, NULL, TIME_PERIODIC 
[解决办法]
 TIME_CALLBACK_EVENT_SET);
mmrTimmer = timeSetEvent(
1, 0, (LPTIMECALLBACK)TimerFunction, NULL, TIME_PERIODIC);
QueryPerformanceCounter(&lnCurrPerfmcCount);
if (0 == lnFirstStartPerfmcCount.QuadPart)
{
nTimmerExist[0] = 1;
lnFirstStartPerfmcCount.QuadPart = lnCurrPerfmcCount.QuadPart;
}
else
{
nIndex = (lnCurrPerfmcCount.QuadPart - lnFirstStartPerfmcCount.QuadPart) / nTimmerLength 
% TIMMER_COUNT;
if (0 == nTimmerExist[nIndex])
{
nTimmerExist[nIndex] = 1;
}
else
{
timeKillEvent(mmrTimmer);
continue;
}
}
nTimmerCount++;
} while (nTimmerCount < TIMMER_COUNT);

do 
{
QueryPerformanceCounter(&lnStartPerfmcCount);

WaitForSingleObject(g_hEvent, INFINITE);

QueryPerformanceCounter(&lnCurrPerfmcCount);

printf("wait time : %lf milliseconds\n",
ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency));
} while (TRUE);

#elif 4 == USE
LARGE_INTEGER lnFrequency = {0};
LARGE_INTEGER lnStartPerfmcCount = {0};
LARGE_INTEGER lnStartPerfmcCountTmp = {0};
LARGE_INTEGER lnFirstStartPerfmcCount = {0};
LARGE_INTEGER lnLastStartPerfmcCount = {0};
LARGE_INTEGER lnCurrPerfmcCount = {0};
lnFrequency.QuadPart = g_lnFrequency.QuadPart;

HANDLE hTimmerTmp = NULL;
HANDLE hTimmer = NULL;
::CreateTimerQueueTimer(
&hTimmer,
NULL,
TimerProc,
NULL,
0,
0,
WT_EXECUTEINTIMERTHREAD);
DeleteTimerQueueTimer(NULL, hTimmer, NULL);

::CreateTimerQueueTimer(
&hTimmer,
NULL,
TimerProc,
NULL,
0,
1,
WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&lnStartPerfmcCount);
lnFirstStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
do 
{
::CreateTimerQueueTimer(
&hTimmer,
NULL,
TimerProc,
NULL,
0,
1,
WT_EXECUTEINTIMERTHREAD);

QueryPerformanceCounter(&lnCurrPerfmcCount);
Judge2:
if (ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency) * 1000 < DELAY_TIME)
{
if (NULL != hTimmerTmp)
{
DeleteTimerQueueTimer(NULL, hTimmer, NULL);


}

hTimmerTmp = hTimmer;
lnStartPerfmcCountTmp.QuadPart = lnCurrPerfmcCount.QuadPart;
}
else
{
if (NULL != hTimmerTmp)
{
hTimmerTmp = NULL;
lnStartPerfmcCount.QuadPart = lnStartPerfmcCountTmp.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
goto Judge2;
}
else
{
lnStartPerfmcCount.QuadPart = lnCurrPerfmcCount.QuadPart;
lnLastStartPerfmcCount.QuadPart = lnStartPerfmcCount.QuadPart;
}
}
} while (ERASE_TIME_IN_MILLISEC(lnLastStartPerfmcCount, lnFirstStartPerfmcCount, lnFrequency) <= 1.0);

if (NULL != hTimmerTmp)
{
DeleteTimerQueueTimer(NULL, hTimmerTmp, NULL);
hTimmerTmp = NULL;
}

do 
{
QueryPerformanceCounter(&lnStartPerfmcCount);

WaitForSingleObject(g_hEvent, INFINITE);

QueryPerformanceCounter(&lnCurrPerfmcCount);

printf("wait time : %lf milliseconds\n",
ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency));
} while (TRUE);

#elif 5 == USE
int nTimmerExist[TIMMER_COUNT] = {0};
int nTimmerLength = DELAY_TIME / 2;
int nTimmerCount = 0;

LARGE_INTEGER lnFrequency = {0};
LARGE_INTEGER lnStartPerfmcCount = {0};
LARGE_INTEGER lnFirstStartPerfmcCount = {0};
LARGE_INTEGER lnCurrPerfmcCount = {0};
lnFrequency.QuadPart = g_lnFrequency.QuadPart;

HANDLE hTimmer;
int nIndex = 0;
do 
{
::CreateTimerQueueTimer(
&hTimmer,
NULL,
TimerProc,
&nTimmerExist[nTimmerCount],
0,
1,
WT_EXECUTEINTIMERTHREAD);
QueryPerformanceCounter(&lnCurrPerfmcCount);
if (0 == lnFirstStartPerfmcCount.QuadPart)
{
nTimmerExist[0] = 1;
lnFirstStartPerfmcCount.QuadPart = lnCurrPerfmcCount.QuadPart;
}
else
{
nIndex = (lnCurrPerfmcCount.QuadPart - lnFirstStartPerfmcCount.QuadPart) / nTimmerLength 
% TIMMER_COUNT;
if (0 == nTimmerExist[nIndex])
{
nTimmerExist[nIndex] = nTimmerCount + 1;
}
else
{
DeleteTimerQueueTimer(NULL, hTimmer, NULL);
continue;
}
}
nTimmerCount++;
} while (nTimmerCount < TIMMER_COUNT);

do 
{
QueryPerformanceCounter(&lnStartPerfmcCount);

WaitForSingleObject(g_hEvent, INFINITE);

QueryPerformanceCounter(&lnCurrPerfmcCount);

printf("wait time : %lf milliseconds\n",
ERASE_TIME_IN_MILLISEC(lnCurrPerfmcCount, lnStartPerfmcCount, lnFrequency));
} while (TRUE);

#endif

return 0;
}

热点排行