Window下的时间计时

152 篇文章 1 订阅

秒计时

1.1 使用time()


函数原型:time_t time(time_t * timer)

功能:返回以格林尼治时间(GMT)为标准,从19701100:00:00到现在的此时此刻所经过的秒数。

: localtime, gmtime, asctime, ctime也可以获得当前系统时间或是标准时间.

注意difftime函数可以计算两个time_t类型的时间的差值例如: difftime(t2, t1), 我们也可以t2 - t1, 但是time()返回的值单位不一定是秒所以使用difftime()更可靠。 

time_t start, end, ttt;  
time(&start);
Sleep(1000);
time(&end);
ttt = difftime(end, start);

毫秒计时

2.1 使用GetTickCount


DWORD GetTickCount(void);

定义: 

For Release configurations, this function returns the number of milliseconds since the device booted, excluding any time that the system was suspended. GetTickCount starts at 0 on boot and then counts up from there.

Release版本中,该函数从0开始计时,返回自设备启动后的毫秒数(不含系统暂停时间)。

For Debug configurations, 180 seconds is subtracted from the the number of milliseconds since the device booted. This allows code that uses GetTickCount to be easily tested for correct overflow handling.

Debug版本中,设备启动后便从计时器中减去180秒。这样方便测试使用该函数的代码的正确溢出处理。

 

Return Values

The number of milliseconds indicates success.

返回值:如正确,返回毫秒数。 

unsigned long lBegin, lEnd;
lBegin = ::GetTickCount();
Sleep(1000);
lEnd = ::GetTickCount();
unsigned long l = lEnd - lBegin;

 

2.2 使用clock


clock_t clock(void); 这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock).

unsigned long  tBegin = ::clock();
Sleep(1000);
unsigned long tEnd = ::clock();
unsigned long ll = (tEnd - tBegin) * 1000 / CLK_TCK;
// 通常CLK_TCK就是1000, 为了效率, tEnd - tBegin就是毫秒数了
// 但是也要看CLK_TCK

 

2.3 使用timeGetTime


函数原型:DWORD timeGetTime(VOID);

功能:返回系统时间,以毫秒为单位。系统时间是从系统启动到调用函数时所经过的毫秒数.

注意这个值是32位的,会在02^32之间循环,约49.71并且精度不是很高可用timeBeginPeriodtimeEndPeriod函数提高timeGetTime函数的精度.

没有精度使用又麻烦而且有其他方法获得毫秒级的计时所以这种方法基本上不使用. 

#include "Mmsystem.h"
#pragma comment(lib,"Winmm.lib")
DWORD dwStart, dwEnd;  
dwStart = timeGetTime();
Sleep(1000);
dwEnd = timeGetTime();
DWORD dw = dwEnd - dwStart;

 

2.4 小结


GetTickCountclock的说明中可以知道:

1. 可以使用GetTickCount计算电脑开机持续时间.

2. 可以使用clock计算某个进程的运行持续时间.

3. timeGetTime需要手动添加lib, 而且精度可能会不好所以甚至可以不使用.


微秒计时

3.1 使用QueryPerformanceFrequency

原型:BOOL QueryPerformanceFrequency(LARGE_INTERGER *lpFrequency);

功能:返回硬件支持的高精度计数器的频率(每秒钟的CPU Tick)

 

原型:BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);

功能:返回高精度计数器的计数值

 

所以消逝时间 = (EndTick - BeginTick) / TickPreSecond;   (单位是秒精度可以达到微秒(看你的硬件而定))

LARGE_INTEGER llTemp, llBegin1, llEnd1;
::QueryPerformanceFrequency(&llTemp); // 获取CPU时钟频率 3220820 kHZ
 
::QueryPerformanceCounter(&llBegin1); // 获取开始计数值 54826082774
Sleep(100);
::QueryPerformanceCounter(&llEnd1);     // 获取结束计数值 54826404859
 
double d = (llEnd1.QuadPart - llBegin1.QuadPart) / (llTemp.QuadPart * 1000.0);  // 单位是秒, 精确到微秒

说明

1. 调用QueryPerformanceFrequency时, 我的电脑返回的值是3220820, 很明显, 其单位是kHZ(我的CPU主频是3.2GHZ)

2. 也就是说3220820倒数一下, 精度也只能达到微秒级了.

 

纳秒计时

4.1 使用RDTSC读取时间标签计数器

4.1.1 RDTSC 指令

这是X86架构CPU汇编指令

指令: RDTSC (操作码: 0x0F 0x31)

功能将时间标签计数器读入EDX:EAX寄存器中.

说明Pentium以上的CPU中,提供了一条机器指令RDTSC来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数返回值的寄存器所以我们可以把这条指令看成是一个普通的函数调用.

inline unsigned __int64 GetRDTSC()  
{   
    __asm RDTSC
}
// 如果编译器不允许直接用RDTSC的话,可以用_emit伪指令直接嵌入该指令的机器码形式0x0F 0x31:
inline unsigned __int64 GetRDTSC()   
{  
    __asm _emit 0x0F
    __asm _emit 0x31
} 
 

GetRDTSC得到CPU跳了多少次如果我们知道跳一次的用时就可以算出持续时间.

跳一次的用时 = 1 / CPU主频 (单位)

 

4.1.2 计算CPU主频


Windows平台下可以使用QueryPerformanceFrequency()函数获得CPU的主频但是在标准C/C++中没有这样的函数.

你可以间接发计算出主频例如:

unsigned __int64 GetCPUHZ()
{
	unsigned __int64 nBegin = GetRDTSC();
	Sleep(1000);
	unsigned __int64 nEnd = GetRDTSC();
	return (nEnd - nBegin);	
}


说明

1. 这个函数的误差在于Sleep(1000)的执行时间不是1可能是1.0002.

2. QueryPerformanceFrequency得到的主频的单位是 kHZ, 也就是说其精度只能达到微秒而不是纳秒.

  

4.1.3 计算持续时间

unsigned __int64 nHZ = GetCPUHZ();
unsigned __int64 nBegin = GetRDTSC();
...
unsigned __int64 nEnd = GetRDTSC();
double dTime = (nEnd - nBegin) * 1.0 / nHZ;// 单位是秒, 精度甚至可以达到纳秒

 

说明:

1. 这里的精度可以达到纳秒但是在纳秒级可能不是很准因为GetCPUHZ() 得到主频有误差.

2. 纳秒计时的粒度最小所以你也可以使用这种方法进行微秒毫秒秒的计时.

 

 

小结

1. 计时与定时不同这里计时可以达到纳秒级但是定时就不能(因为执行一条指令可能至少要100纳秒).

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现在 Windows Form 应用程序中的倒计时暂停,你可以使用 Timer 控件和一些变量来实现。下面是一个简单的示例代码: 1. 在 Windows Form 中添加一个 Timer 控件,设置其 Interval 属性为 1000(表示 1 钟)。 2. 创建一个 int 类型的变量来表示倒计时的总时间,例如 totalSeconds,赋予其初始值。 3. 在 Timer 的 Tick 事件处理程序中,每次 Timer 触发时将 totalSeconds 减去 1,并将剩余时间显示到 UI 上。 4. 添加一个按钮来控制倒计时的开始和暂停。在按钮的 Click 事件处理程序中,判断当前状态是开始还是暂停,然后相应地改变 Timer 的 Enabled 属性,并修改按钮的文本。 下面是一个示例代码: ```csharp public partial class Form1 : Form { private int totalSeconds = 60; // 倒计时的总时间,单位为 private bool isPaused = false; // 记录当前倒计时的状态 public Form1() { InitializeComponent(); timer1.Interval = 1000; } private void timer1_Tick(object sender, EventArgs e) { if (totalSeconds > 0) { totalSeconds--; label1.Text = totalSeconds.ToString(); } else { timer1.Enabled = false; MessageBox.Show("Time's up!"); } } private void button1_Click(object sender, EventArgs e) { if (isPaused) { timer1.Enabled = true; button1.Text = "Pause"; } else { timer1.Enabled = false; button1.Text = "Start"; } isPaused = !isPaused; } } ``` 在上面的示例代码中,我们使用了一个标志变量 isPaused 来记录当前倒计时的状态。在按钮的 Click 事件处理程序中,我们判断当前状态是开始还是暂停,并根据需要修改 Timer 的 Enabled 属性和按钮的文本。在 Timer 的 Tick 事件处理程序中,我们每次将总时间减去 1,并将剩余时间显示到 UI 上。当总时间为 0 时,我们禁用 Timer 并弹出一个消息框提示用户倒计时结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值