定时函数的应用综述

  当我们在衡量一个函数的运行时间,或者是判断一个算法的时间效率,或者在程序中我们需要一个定时器来定时执行一个特定的操作,如闹铃、时钟、多媒体、游戏动画等,都要用到时间函数。编译器和时间函数为我们提供了很多时间函数,而这些函数的精度和用法也是各不相同的。下面我们就对几种常见的定时函数进行比较、详述:
1、 Sleep函数
用法
精度
原理及说明
备注
VOID Sleep(
 DWORD dwMilliseconds 
 // 休眠的毫秒数
);
其精度很低,系统越忙,精度越低,其精度取决于当前线程及其他线程的优先级以及线程数量等因素
Sleep 函数是使调用Sleep函数的线程休眠,线程主动放弃时间片。当经过指定的时间间隔后,再启动线程,继续执行代码。Sleep函数并不能起到定时的作用,主要作用是延时。在一些多线程中可能会看到Sleep(0);其主要目的是让出时间片。
 
Sleep(1000);//休眠一秒钟
当你要创建一个窗口是使用这个函数必须要小心。因为当一个进程创建一个窗口时,它必须处理消息,而消息广播被发送到系统所有的窗口中,这时你如果在一个线程中使用了 Sleep 函数来无限延迟,可能会导致系统死锁。所以在此时你可以应用函数 MsgWaitForMultipleObjects MsgWaitForMultipleObjectsEx 来代替 Sleep MSDN
 
2、 MFC中的timer事件
用法
精度
原理及说明
备注
先使用SetTimer()来定时
再在程序中增加定时响应函数OnTimer()并在此函数中增加相应的处理语句完成时间到时的操作
精度在毫秒级别,一般其响应时间为55ms,且系统越忙精度越差。
原理与Sleep一样,不同的是timer是一个定时器,可以指定回调函数,默认为OnTimer().
常用于做电子时钟或者在游戏动画中使用它。
 
3、 C中的Time应用
用法
精度
原理及说明
备注
time_t t;
time(&t);
Time函数是获取当前时间
秒级别
用于获取当前时间
比如我们做一个电子时钟,就可以用它来获取系统当前时间
4、 COM中的COledateTime,COleDateTimeSpan类的使用
用法
精度
原理及说明
备注
COleDateTime    start_time= COleDateTime::GetCurrentTime();
COleDateTimeSpan    end_time= COleDateTime::GetCurrentTime()-start_time;
While(end_time.GetTotalSeconds() < 2) {
    // 处理延时或定时期间能处理其他的消息
    DoSomething()
    end_time = COleDateTime::GetCurrentTime-start_time;
}
秒级别
以上代表延时2秒,而这两秒内我们可以循环调用DoSomething(),从而实现在延时的时候我们也能够处理其他的函数,或者消息。
COleDateTime,COleDateTimeSpan是MFC中CTime,CTimeSpan在COM中的应用,所以,上面的方法对于CTime,CTimeSpa同样有效。
 
5、 C语言中的时钟周期clock的使用
用法
精度
原理及说明
备注
clock_t start = clock();
Sleep(100);
clock_t end = clock();
double d = (double)(start - end) / CLOCKS_PER_SEC;
ms级别,对于短时间内的定时或者延时可以达到ms级别,对于时间比较长的定时或者延迟精度还是不够。
原理:clock()是获取计算机启动后的时间间隔。
在windows下 CLOCKS_PER_SEC为1000。
 
6、 Windows下的GetTickCount的使用
用法
精度
原理及说明
备注
DWORD start = GetTickCount();
Sleep(100);
DWORD end = GetTickCount();
其时间精度要比clock高,
Windows NT 3.5 以后
10ms.
Windows NT 3.1
16ms.
Windows 95 and later
55ms
GetTickCount()是获取系统启动后的时间间隔。通过进入函数开始定时,到退出函数结束定时,从而可以判断出函数的执行时间,这种时间也并非是函数或者算法的真实执行时间,因为在函数和算法线程不可能一直占用CPU,对于所有判断执行时间的函数都是一样,不过基本上已经很准确,可以通过查询进行定时。GetTickCount()和Clock()函数是向主板BIOS要real time clock时间,会有中断产生,以及延迟问题。
常用于多媒体
7、 Windows下的timeGetTime使用
用法
精度
原理及说明
备注
timeBeginPeriod(1);
DWORD start = timeGetTime();
Sleep(100);
DWORD end = timeGetTime();
timeEndPeriod(1);
毫秒
与GetTickCount()相当。但是和GetTickCount相比,timeGetTime可以通过timeBeginPeriod,timeEndPeriod设置定时器的最小解析精度
timeGetTime也时常用于多媒体定时器中,可以通过查询进行定时。通过查询进行定时,本身也会影响定时器的定时精度。
timeBeginPeriod,
timeEndPeriod必须成对出现。
需要包含Mmsystem.h,Windows.h,加入静态库Winmm.lib
Windows CE 下需要包含需要包含Mmsystem.h,Windows.h,
加入静态库mmtimer.lib
 
8、 Windows 下的TimeSetEvent函数的使用
用法
精度
原理及说明
备注
需要调用:
timeGetDevCaps()
timeBeginPeriod()
然后调用 TimeSetEvent()
最后调用:timeKillEvent()
定义一个回调函数:
static VOID CALLBACK StopwatchTimer(
UINT uTimerID,
UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)

毫秒
Timer是一个定时器,而以上我们提到几种时间函数或者类型,实现定时功能只能通过轮训来实现,也就是必须另外创建一个线程单独处理,这样会影响定时精度,好在windows提供了内置的定时器timeSetEvent。 具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在 lpFunction回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。原理:可以理解为代回调函数的timeGetTime
timeBeginPeriod
timeEndPeriod置定时器的最小解析精度必须成对出现。
需要包含Mmsystem.h,Windows.h,加入静态库Winmm.lib
Windows CE 下需要包含需要包含Mmsystem.h,Windows.h,
加入静态库mmtimer.lib
 
9、 高精度时控函数QueryPerformanceFrequency,QueryPerformanceCounter使用
用法
精度
原理及说明
备注
LARGE_INTEGER m_nFreq;
LARGE_INTEGER m_nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&m_nFreq);
 // 获取时钟周期
QueryPerformanceCounter(&m_nBeginTime);
 // 获取时钟计数
Sleep(100);
QueryPerformanceCounter(&nEndTime);
cout << (nEndTime.QuadPart-
m_nBeginTime.QuadPart)*
1000/m_nFreq.QuadPart
<< endl;
计算机获取硬件支持,精度较高,可以用来判断其他时间函数的精度范围
:CPU上也有一个计数器,以机器的clock为单位,可以通过rdtsc读取,而不用中断,因此其精度与系统时间相当。
 
 
小结:以上提到的9种时间函数,由于他们的用处不同,其精度也有很大的差异,用户可以根据不同的需求选择合适的时间函数。
本文原始资料来源于网络,经个人加工形成,有些函数由于没有经过自己的测试,资料不一定准确,在选择了具体的函数之后,使用时尚须查阅该函数具体的资料。
我在程序中使用过的函数举例:
1:Sleep(1000)
//延时1s,多用于多线程程序中,如果在单个线程的程序中使用,有类似死机现象。
2、Timer事件:
该函数使用比较简单,但由于其精度与系统繁忙程度有关,在不需精确定时的场合应用非常好用,但如果需要精确定时,建议不要使用;
(1)    定时 setTimer(1,1000,NULL)//为定时器一设置一个1秒的周期
(2)    在应用程序中添加OnTime()
{
 CDC * pDC;
 pDC->TextOut(100,100,“This is a test!”);
}//消息响应函数,在该函数中处理你想有响应的事件。
3、TimeSetEvent()函数
// 加入静态链接库Winmm.lib(Windows xp),mmTimer.lib(Windows CE)
#include <Mmsystem.h> // 已经包含了的头文件
#include <Windows.h>
# define ONE_MILLI_SECOND 100 // 定义1ms和2s时钟间隔,以ms为单位 ;
# define TWO_SECOND 2000
# define TIMER_ACCURACY 1 // 定义时钟分辨率,以ms为单位
UINT wTimerRes_1ms,wTimerRes_2s; // 定义时间间隔
UINT wAccuracy; // 定义分辨率
UINT TimerID_1ms,TimerID_2s; // 定义定时器句柄
 
static VOID CALLBACK OneMilliSecondProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
    // 定义计数器
    static int ms = 0 ;
    CDAQView *app = (CDAQView *)dwUser;
    // 取得系统时间,以ms为单位
    DWORD osBinaryTime = GetTickCount();
    // 输出计数器值和当前系统时间
    app->Timer();
}
CDAQView::CDAQView()
{
    // TODO: add construction code here
 
    // 给时间间隔变量赋值
    wTimerRes_1ms = ONE_MILLI_SECOND;
    wTimerRes_2s = TWO_SECOND;
    TIMECAPS tc;
    // 利用函数timeGetDevCaps取出系统分辨率的取值范围,如果无错则继续;
    if (timeGetDevCaps(&tc, sizeof (TIMECAPS))==TIMERR_NOERROR)
    {
    wAccuracy=min(max(tc.wPeriodMin, // 分辨率的值不能超出系统的取值范围
    TIMER_ACCURACY),tc.wPeriodMax);
    // 调用timeBeginPeriod函数设置定时器的分辨率
    timeBeginPeriod(wAccuracy);
 
}
 
CDAQView::~CDAQView()
{
    timeKillEvent(TimerID_1ms); // 删除两个定时器
// 删除设置的分辨率
    timeEndPeriod(wAccuracy);
}
void CDAQView::StartOneMilliSecondTimer()
{   
    if ((TimerID_1ms = timeSetEvent(wTimerRes_1ms, wAccuracy,
        (LPTIMECALLBACK) OneMilliSecondProc, // 回调函数;
        (DWORD) this , // 用户传送到回调函数的数据;
        TIME_PERIODIC)== 10 )) // 周期调用定时处理函数;
    {
            AfxMessageBox( " 不能进行定时!" , MB_OK | MB_ICONASTERISK);
    }
    else
    {
    }  // 不等于0表明加装成功,返回此定时器的句柄;
}
 
void CDAQView::InitializeTimer()
{
    StartOneMilliSecondTimer();
}
CDAQView::Timer()
{
}
 
 
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值