精确获取时间.docx

上传人:b****6 文档编号:3558505 上传时间:2022-11-23 格式:DOCX 页数:31 大小:51.85KB
下载 相关 举报
精确获取时间.docx_第1页
第1页 / 共31页
精确获取时间.docx_第2页
第2页 / 共31页
精确获取时间.docx_第3页
第3页 / 共31页
精确获取时间.docx_第4页
第4页 / 共31页
精确获取时间.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

精确获取时间.docx

《精确获取时间.docx》由会员分享,可在线阅读,更多相关《精确获取时间.docx(31页珍藏版)》请在冰豆网上搜索。

精确获取时间.docx

精确获取时间

精确获取时间(QueryPerformanceCounter)

LARGE_INTEGERtima,timb; 

QueryPerformanceCounter(&tima);

在WindowsServer2003和WindowsXP中使用QueryPerformanceCounter函数的程序可能执行不当

QueryPerformanceCounter來精確計算執行時間

QueryPerformanceCounter來精確計算執行時間

//這個程式展示了如何使用QueryPerformanceCounter來精確計算執行時間

//代码

 

1.LARGE_INTEGER m_liPerfFreq={0};

2. //获取每秒多少CPU Performance Tick 

3. QueryPerformanceFrequency(&m_liPerfFreq); 

4. 

5. LARGE_INTEGER m_liPerfStart={0};

6. QueryPerformanceCounter(&m_liPerfStart);

7. 

8. for(int i=0; i< 100; i++)

9.  cout << i << endl;

10.

11. LARGE_INTEGER liPerfNow={0};

12. // 计算CPU运行到现在的时间

13. QueryPerformanceCounter(&liPerfNow);

14.

15. int time=( ((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);

16.

17. char buffer[100];

18. sprintf(buffer,"執行時間 %d millisecond ",time);

19.

20. cout<

21.

22.

QueryPerformanceCounter()这个函数返回高精确度性能计数器的值,它可以以微妙为单位计时.但是QueryPerformanceCounter()确切的精确计时的最小单位是与系统有关的,所以,必须要查询系统以得到QueryPerformanceCounter()返回的嘀哒声的频率.

QueryPerformanceFrequency()提供了这个频率值,返回每秒嘀哒声的个数.

计算确切的时间是从第一次调用QueryPerformanceCounter()开始的

假设得到的LARGE_INTEGER为nStartCounter,过一段时间后再次调用该函数结束的,

设得到nStopCounter.

两者之差除以QueryPerformanceFrequency()的频率就是开始到结束之间的秒数.由于计时函数本身要耗费很少的时间,要减去一个很少的时间开销.但一般都把这个开销忽略.公式如下:

   

                        nStopCounter-nStartCounter 

ElapsedTime=-------------------------------------overhead 

frequency 

doubletime=(nStopCounter.QuadPart-nStartCounter.QuadPart)/frequency.QuadPart

这两个函数是VC提供的仅供Windows95及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。

QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:

BOOLQueryPerformanceFrequency(LARGE_INTEGER*lpFrequency);

BOOLQueryPerformanceCounter(LARGE_INTEGER*lpCount);

  数据类型ARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构, 其具体用法根据编译器是否支持64位而定。

该类型的定义如下:

typedefunion_LARGE_INTEGER

{

struct

{

DWORDLowPart;//4字节整型数

LONGHighPart;//4字节整型数

};

LONGLONGQuadPart;//8字节整型数

}LARGE_INTEGER;

  在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。

下列代码实现1ms的精确定时:

 

1.       LARGE_INTEGER litmp; 

2.       LONGLONG QPart1,QPart2;

3.       double dfMinus, dfFreq, dfTim; 

4.       QueryPerformanceFrequency(&litmp);

5.       dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率

6.       QueryPerformanceCounter(&litmp);

7.       QPart1 = litmp.QuadPart;// 获得初始值

8.       do

9.       {

10.          QueryPerformanceCounter(&litmp);

11.          QPart2 = litmp.QuadPart;//获得中止值

12.          dfMinus = (double)(QPart2-QPart1);

13.          dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒

14.       }while(dfTim<0.001);

  其定时误差不超过1微秒,精度与CPU等机器配置有关。

下面的程序用来测试函数Sleep(100)的精确持续时间:

1.       LARGE_INTEGER litmp; 

2.       LONGLONG QPart1,QPart2;

3.       double dfMinus, dfFreq, dfTim; 

4.       QueryPerformanceFrequency(&litmp);

5.       dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率

6.       QueryPerformanceCounter(&litmp);

7.       QPart1 = litmp.QuadPart;// 获得初始值

8.       Sleep(100);

9.       QueryPerformanceCounter(&litmp);

10.       QPart2 = litmp.QuadPart;//获得中止值

11.       dfMinus = (double)(QPart2-QPart1);

12.       dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒    

  由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。

下列代码实现1微秒的精确定时:

 

1.       LARGE_INTEGER litmp; 

2.       LONGLONG QPart1,QPart2;

3.       double dfMinus, dfFreq, dfTim; 

4.       QueryPerformanceFrequency(&litmp);

5.       dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率

6.       QueryPerformanceCounter(&litmp);

7.       QPart1 = litmp.QuadPart;// 获得初始值

8.       do

9.       {

10.          QueryPerformanceCounter(&litmp);

11.          QPart2 = litmp.QuadPart;//获得中止值

12.          dfMinus = (double)(QPart2-QPart1);

13.          dfTim = dfMinus / dfFreq;// 获得对应的时间值,单位为秒

14.       }while(dfTim<0.000001);

其定时误差一般不超过0.5微秒,精度与CPU等机器配置有关。

VC多线程编程(转)

VC中多线程使用比较广泛而且实用,在网上看到的教程.感觉写的挺好.

一、问题的提出

编写一个耗时的单线程程序:

  新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下:

 

void CSingleThreadDlg:

:

OnSleepSixSecond() 

{

 Sleep(6000); //延时6秒

}

  编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。

为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。

二、多线程概述

  进程和线程都是操作系统的概念。

进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。

  线程是进程内部的一个执行单元。

系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。

主执行线程终止了,进程也就随之终止。

  每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。

用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。

一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。

  多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。

要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。

由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。

这一点在多线程编程时应该注意。

  Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。

Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。

三、Win32 API对多线程编程的支持

  Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。

下面将选取其中的一些重要函数进行说明。

 

1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,

                 DWORD dwStackSize,

                 LPTHREAD_START_ROUTINE lpStartAddress,

                 LPVOID lpParameter,

                 DWORD dwCreationFlags,

                 LPDWORD lpThreadId);

该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:

lpThreadAttributes:

指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL; 

dwStackSize:

指定了线程的堆栈深度,一般都设置为0; 

lpStartAddress:

表示新线程开始执行时代码所在函数的地址,即线程的起始地址。

一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名; 

lpParameter:

指定了线程执行时传送给线程的32位参数,即线程函数的参数; 

dwCreationFlags:

控制线程创建的附加标志,可以取两种值。

如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用; 

lpThreadId:

该参数返回所创建线程的ID; 

如果创建成功则返回线程的句柄,否则返回NULL。

 

2、DWORD SuspendThread(HANDLE hThread);

该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。

 3、DWORD ResumeThread(HANDLE hThread);

该函数用于结束线程的挂起状态,执行线程。

 4、VOID ExitThread(DWORD dwExitCode);

该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。

其中参数dwExitCode用来设置线程的退出码。

 5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

  一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。

各参数含义如下:

hThread:

将被终结的线程的句柄; 

dwExitCode:

用于指定线程的退出码。

 

  使用TerminateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。

因此,一般不建议使用该函数。

 

6、BOOL PostThreadMessage(DWORD idThread,

   UINT Msg,

   WPARAM wParam,

   LPARAM lParam);

该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回。

idThread:

将接收消息的线程的ID; 

Msg:

指定用来发送的消息; 

wParam:

同消息有关的字参数; 

lParam:

同消息有关的长参数; 

调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。

四、Win32 API多线程编程例程

例程1 MultiThread1

建立一个基于对话框的工程MultiThread1,在对话框IDD_MULTITHREAD1_DIALOG中加入两个按钮和一个编辑框,两个按钮的ID分别是IDC_START,IDC_STOP ,标题分别为“启动”,“停止”,IDC_STOP的属性选中Disabled;编辑框的ID为IDC_TIME ,属性选中Read-only;

  

在MultiThread1Dlg.h文件中添加线程函数声明:

 void ThreadFunc();

注意,线程函数的声明应在类CMultiThread1Dlg的外部。

 在类CMultiThread1Dlg内部添加protected型变量:

  HANDLE hThread;

 DWORD ThreadID;

分别代表线程的句柄和ID。

 

  

在MultiThread1Dlg.cpp文件中添加全局变量m_bRun :

 volatile BOOL m_bRun;

m_bRun 代表线程是否正在运行。

你要留意到全局变量 m_bRun 是使用 volatile 修饰符的,volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。

对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。

编写线程函数:

 void ThreadFunc()

{

 CTime time;

 CString strTime;

 m_bRun=TRUE;

 while(m_bRun)

 {

  time=CTime:

:

GetCurrentTime();

  strTime=time.Format("%H:

%M:

%S");

  :

:

SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);

  Sleep(1000);

 }

}

该线程函数没有参数,也不返回函数值。

只要m_bRun为TRUE,线程一直运行。

双击IDC_START按钮,完成该按钮的消息函数:

 void CMultiThread1Dlg:

:

OnStart() 

{

 // TODO:

 Add your control notification handler code here

 hThread=CreateThread(NULL,

  0,

  (LPTHREAD_START_ROUTINE)ThreadFunc,

  NULL,

  0,

  &ThreadID);

 GetDlgItem(IDC_START)->EnableWindow(FALSE);

 GetDlgItem(IDC_STOP)->EnableWindow(TRUE);

}

双击IDC_STOP按钮,完成该按钮的消息函数:

 void CMultiThread1Dlg:

:

OnStop() 

{

 // TODO:

 Add your control notification handler code here

 m_bRun=FALSE;

 GetDlgItem(IDC_START)->EnableWindow(TRUE);

 GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

}

编译并运行该例程,体会使用Win32 API编写的多线程。

 

例程2 MultiThread2

  该线程演示了如何传送一个一个整型的参数到一个线程中,以及如何等待一个线程完成处理。

建立一个基于对话框的工程MultiThread2,在对话框IDD_MULTITHREAD2_DIALOG中加入一个编辑框和一个按钮,ID分别是IDC_COUNT,IDC_START ,按钮控件的标题为“开始”; 

在MultiThread2Dlg.h文件中添加线程函数声明:

 void ThreadFunc(int integer);

注意,线程函数的声明应在类CMultiThread2Dlg的外部。

在类CMultiThread2Dlg内部添加protected型变量:

  HANDLE hThread;

 DWORD ThreadID;

分别代表线程的句柄和ID。

  

打开ClassWizard,为编辑框IDC_COUNT添加int型变量m_nCount。

在MultiThread2Dlg.cpp文件中添加:

void ThreadFunc(int integer)

{

 int i;

 for(i=0;i

 {

  Beep(200,50);

  Sleep(1000);

 }

双击IDC_START按钮,完成该按钮的消息函数:

 void CMultiThread2Dlg:

:

OnStart() 

{

 UpdateData(TRUE);

 int integer=m_nCount;

 hThread=CreateThread(NULL,

  0,

  (LPTHREAD_START_ROUTINE)ThreadFunc,

  (VOID*)integer,

  0,

  &ThreadID);

 GetDlgItem(IDC_START)->EnableWindow(FALSE);

 WaitForSingleObject(hThread,INFINITE);

 GetDlgItem(IDC_START)->EnableWindow(TRUE);

}

顺便说一下WaitForSingleObject函数,其函数原型为:

DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);

hHandle为要监视的对象(一般为同步对象,也可以是线程)的句柄; 

dwMilliseconds为hHandle对象所设置的超时值,单位为毫秒; 

  当在某一线程中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态。

如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。

参数dwMilliseconds有两个具有特殊意义的值:

0和INFINITE。

若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。

  本例程调用该函数的作用是按下IDC_START按钮后,一直等到线程返回,再恢复IDC_START按钮正常状态。

编译运行该例程并细心体会。

例程3 MultiThread3 

传送一个结构体给一个线程函数也是可能的,可以通过传送一个指向结构体的指针参数来完成。

先定义一个结构体:

 

typedef struct

{

 int firstArgu,

 long secondArgu,

}myType,*pMyType;

创建线程时CreateThread(NULL,0,threadFunc,pMyType,…);

在threadFunc函数内部,可以使用“强制转换”:

int intValue=((pMyType)lpvoid)->firstArgu;

long longValue=((pMyType)lpvoid)->seconddArgu;

……

例程3 MultiThread3将演示如何传送一个指向结构体的指针参数。

 

建立一个基于对话框的工程MultiThread3,在对话框IDD_MULTITHREAD3_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始” ,一个进度条IDC_PROGRESS1

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 小升初

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1