VC中使用Sleep函数的注意事项

VC中的Sleep函数在延时应用中很好用,比如通信程序中,一方需等待另一方若干个毫秒后再处理,或者在死循环中,让出CPU不至于资源占用100%等等;

但是,在界面操作中不要使用Sleep函数,比如按钮事件中,不要调用这个函数,否则会出现意外的情况!!那么如何处理延时一段时间执行呢?使用定时器,将按钮事件中调用Sleep函数中的地方,改为启动一个一段时间执行后的定时器:SetTimer(定时器编号,毫秒数后执行,NULL);执行的动作放到定时器回调函数中执行,如果仅执行一次的,那么进到回调函数后首先将定时器关闭(即不是周期执行);

这样做的好处是,所有的“操作”(处理),都是在“本类”中。


另一个方案是启动一个线程:AfxBeginThread(处理回调函数,传递给回调函数的参数);但是也不建议使用!!因为,一般使用该函数都是这样使用,调用时:

 

 

 

 

AfxBeginThread(Fn, this); //this是“目前正在处理这个类”的指针

 

 

而在回调函数Fn中一般:

 

 

UINT Fn( LPVOID pParam )
{
	CMyDlg *pDlg = (CMyDlg *)pParam;//切换到“正在处理”的类中

	//其他处理

	return 1L;
}

 

这涉及到RTTI,微软MFC在这方面做得不是太好(我在使用codeproject上的一些派生类控件就遇到了几个不解的问题,不知道是微软MFC的问题,还是那些派生类控件的问题),保守一点,使用定时器,可以避免这方面的弯路!

 

2. Sleep()的精度是可以保证的,如Sleep(4),能保证延时4个毫秒,但是不能用GetTickCOunt()函数来探测(最小精度15毫秒,不信自己验证),而是需使用:

 

#include <windows.h>
#include <stdio.h>

//链接库
#pragma comment(lib, "Winmm.lib")

void main()
{
	timeBeginPeriod(1);
	Sleep(100);

	int j=0;

	//探测10次Sleep的延时
	for(int i=0; i<10; i++)
	{

		DWORD s = timeGetTime();//开始时间(毫秒级)

		//延时函数
		Sleep(2);
		//for (j=0; j<10000000; j++);//测算34~40毫秒,所以for循环每条指令为3~4个ns

		DWORD e = timeGetTime();//结束时间(毫秒级)

		printf("%d\n", e-s);//
	}

}


小心,在一个复杂的工程中,使用windows多媒体库,有可能对原有系统的功能造成不稳定,如CPU占用率过高、破坏原有的定时频率等!!

 

 

 

 

2015_09_27编辑:在intel的x86上,还是采用“查询机器内硬件计数器工作频率”方式更好用:

2018_07_20编辑:使用时,要将该线程绑定到某个cpu上:

 

 

// TestCmd.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "TestCmd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 唯一的应用程序对象

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// 初始化 MFC 并在失败时显示错误
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: 更改错误代码以符合您的需要
		_tprintf(_T("错误: MFC 初始化失败\n"));
		nRetCode = 1;
	}
	else
	{
		//将该线程绑定到CPU0上, 第二个参数为一个掩码,
		DWORD_PTR mask=SetThreadAffinityMask(GetCurrentThread(), 0x0001);
		printf("绑定到: %x\n", mask);


		LARGE_INTEGER freq;
		LARGE_INTEGER c1={0}, c2={0}, c={0};

		//查询该机器本身的工作频率,并检查是否支持
		BOOL b = QueryPerformanceFrequency(&freq);
		if(b)
			printf("频率 = %I64d\n", freq.QuadPart);
		else
			printf("QueryPerformanceFrequency 失败\n");



		//下面检验Sleep(1)的精度
		int i;
		for (i=0; i<100; i++)
		{
			QueryPerformanceCounter(&c1);
			c.QuadPart = c1.QuadPart - c2.QuadPart;
			printf("%I64d, %.5fs\n", 
				c.QuadPart,							//计数器差
				c.QuadPart/(double)freq.QuadPart	//周期值,单位:秒
				);
			


			Sleep(1);

			c2 = c1;
		}

		getchar();
	}

	return nRetCode;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 在vc80,要实现程序的微秒级别的sleep,可以使用Windows提供的Sleep函数来实现。Sleep函数可以让程序休眠一定的毫秒数。 由于Sleep函数的最小单位是毫秒,要实现微秒级别的sleep,可以将需要休眠的微秒数转换成对应的毫秒数。例如,如果需要休眠50微秒,可以将其转换成0.05毫秒。然后调用Sleep函数休眠这个毫秒数即可。 然而,Sleep函数的精确度是受限的,不能保证休眠精确到微秒级别。要实现更精确的休眠,可以使用高精度定时器来进行实现。vc80可以使用QueryPerformanceFrequency函数获取计时器的频率,使用QueryPerformanceCounter函数获取当前时间,并计算出需要休眠的时间差。 首先,调用QueryPerformanceFrequency函数获取计时器的频率,保存在一个变量。然后调用QueryPerformanceCounter函数获取当前时间,保存在另一个变量。接下来,根据需要休眠的微秒数计算出对应的时间差。将这个时间差转换成以秒为单位的结果。然后将这个结果传入Sleep函数进行休眠。 需要注意的是,使用高精度定时器进行休眠的方式可能会导致休眠时间不准确,因为其精确度还受到其他因素的影响,如系统负载。若要实现更高精度的休眠,可能需要使用其他更为复杂的方法。 ### 回答2: 在VC80要实现微秒级别的程序休眠,可以使用Win32 APISleep和timeBeginPeriod函数结合使用Sleep是一个简单的Win32函数,可以让当前线程休眠指定的时间。但是它的最小精度是毫秒级别,无法实现微秒级别的休眠。 而timeBeginPeriod函数可以设置系统定时器的最小精度。该函数的参数指定的是定时器精度,单位是毫秒。通过调用timeBeginPeriod(1)时,可以将系统定时器的最小精度设置为1毫秒,从而实现毫秒级别的Sleep。同样地,如果将系统定时器的最小精度设置为1微秒,那么通过Sleep就可以实现微秒级别的休眠。 具体代码如下: ```cpp #include <windows.h> int main() { timeBeginPeriod(1); // 设置系统定时器的最小精度为1毫秒 Sleep(1); // 休眠1毫秒,当然也可以是其他数值 timeBeginPeriod(1); // 设置系统定时器的最小精度为1微秒 Sleep(1); // 休眠1微秒,当然也可以是其他数值 timeEndPeriod(1); // 恢复系统定时器的精度为原来的值 return 0; } ``` 以上代码,通过调用timeBeginPeriod(1)将系统定时器精度设置为1微秒,并通过Sleep(1)来实现微秒级别的休眠。需要注意的是,在结束程序前一定要调用timeEndPeriod(1)来恢复系统定时器的精度为原来的值,避免影响其他程序的正常运行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值