首页 > 代码库 > 关于程序调试、高精度计时器和sleep函数

关于程序调试、高精度计时器和sleep函数

来自http://acm.sdibt.edu.cn/blog/?p=37

一般在调试程序时都会设置断点,并且单步跟踪,但是当遇到数据比较多或者无法单步跟踪的情况(如图形程序)。遇到这种情况怎么办?

一般的解决办法是输出到文件,但是输出到文件还是无法单步跟踪的。以前我也遇到过这样的问题,没有办法,只好在人为有问题的地方打fprintf不停的输出到文件。不过通过这几天的工作我学到一种新的方法,这个可以开启编译器(VS2005之类)的输出功能。在编译器的输出框中输出你想要看到的变量。

下面是示例。比如我现在有一个变量是int i,我要在程序运行中看它的值改变的情况。

int i;

char pBuf[MAX_PATH];

StringCbPrintfA(pBuf,sizeof(pBuf),”%d\n”,i);

OutputDebugStringA(pBuf);

注意函数名字后面的A说明使用的ASCII编码。如果是W或者是编译器默认设置应该是Unicode,那应当这么写

int i;

WCHAR pBuf[MAX_PATH];

StringCbPrintfW(pBuf,sizeof(pBuf),TEXT(“%d\n”),i);

OutputDebugStringW(pBuf);

还有一点要注意的OutputDebugString函数属于Win32API包含在WinBase.h头文件中,可以在项目头部包含<windows.h>

为了让大家更清楚的了解我写了一个非常短的测试程序,大家可以好到编译器里看看效果

#include <Windows.h>

#include <strsafe.h>
#include <stdio.h>

int main()
{
 int i;
 char pBuf[MAX_PATH];
 for(i=0;i<100;i++)
 {
  StringCbPrintfA(pBuf,sizeof(pBuf),”%d\n”,i);
  OutputDebugStringA(pBuf);
 }
 return 0;

}

一定要注意头文件的顺序,不然编译时会出现Windows的API函数定义错误。

下面将关于高精度计时器的问题。

可能大家在写程序的时候用到过GetTickCount这个函数来做计时器,表面上这个函数返回的值是以毫秒作为单位的,所以可能认为它的精度应该在一毫秒。但是这是完全错误的,根据MSDN上的说明这个函数有10到16毫秒的误差,而且这个函数在线程切换时会被挂起,所以其误差可能不止16毫秒,尤其是系统比较忙的时候。

下面来介绍高精度计时器,这个是基于硬件的,需要从CPU获取其频率。

具体函数和代码如下:

LARGE_INTEGER  m_startTime,m_endTime;   //开始和结束时间,其实是CPU始终跳动的次数

LARGE_INTEGER m_ticksPerSecond;//CPU每秒跳动的次数

QueryPerformanceFrequency(&m_ticksPerSecond);//获取CPU每秒跳动次数

QueryPerformanceCounter(&m_startTime);//获取开始时CPU已经跳过的次数

……执行其他代码

QueryPerformanceCounter(&m_endTime);//获取结束时CPU跳过的频率

//计算用的时间,单位是s

double seconds=((double)m_endTime.QuadPart-(double)m_startTime.QuadPart)/(double)m_ticksPerSecond.QuadPart;

据说这个计数器可以比较出++和+之间运算时间上的差别,不过我没试过,有兴趣大家可以试试。

最后说一下sleep函数。

首先说这个函数的参数是毫秒数,初看这个函数可能觉得它的功能是让程序休息多少毫秒。但是这是错误的。首先,大家用的windows系统根本没有一个非常精确的计时标准(前面讲了高精度计时器,其实它也存在误差,只是比较小而已)。其次,windows系统是一个多任务系统。

为什么说这两点的呢?其实归根结底这两点是一点,就是windows系统是一个多任务系统。由于要涉及多个线程或者进程的切换和调度,而每个进程或者线程运行的时间不同,进程切换的时间也不同,当进程或者线程被挂起之后,其中的计时器函数也相应被挂起,所以无从统计精确的时间(前面的计时器在计时时其实已经将进程等待和切换时间算在程序运行时间里了)。而同样有这样一个问题,程序休息多少毫秒这个时间也是不精确的。

当然前面讲的还没有讲到关键。关键是这个我们被这个函数的名字骗了。在windows中sleep(0)的意思是放弃当前CPU时间或者CPU时间的竞争,但在下一个调度开始时参加CPU时间的竞争,所以这个sleep(0)不是休息0毫秒,而是要放弃当前的CPU时间。而sleep(time),time为大于零的值则代表,在未来的time毫秒内不参与CPU时间的竞争,所以由于上段所述原因,可能在time毫秒以后调用sleep函数的进程还是得不到CPU时间也就是无法马上醒来,因为这时可能还轮不到它用CPU。所以sleep(time)只能保证进程最少休息time时间。

对于程序中调用sleep函数,主要是防止程序占用太多的CPU时间而使其他程序得不到CPU。

这些是我工作两周来学到的东西,虽然比较菜,但是觉得比较有用。

放在这里与大家分享了。

关于程序调试、高精度计时器和sleep函数