VC++几种定时器使用方法的归纳

        在游戏编写中,我遇到一个现象:在连续按键的相应过程中,WM_TIMER消息一直没有得到相应。

        查阅网上的资料后发现,WM_TIMER的消息属于最低优先级的消息,当线程的队列中没有其他消息时,才检索该消息。而且设置的定时器不精确(大概57ms左右的精度),所以会出现了延迟的结果。于是,我想看看有没有其他的定时器方式,大致有以下几个方式:

        1.WM_TIMER:SetTimer,OnTimer,KillTimer这样的使用方式(最简单的);

        2.等待定时器(WaitableTimer):

        (1)一种是,多线程+WaitableTimer实现定时器功能(未使用响应函数的方法),相关代码如下:

int CWaitableTimerTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	// 创建定时器线程,并立即执行
	m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TimerThreadProc, (LPVOID)this, 0, &ThreadID);
	return 0;
}
// 定时器线程执行函数
void TimerThreadProc(LPVOID lpArg)
{
	// 多线程+WaitableTimer实现定时器功能(未使用定时响应函数版本)
	CWaitableTimerTestView *pView = (CWaitableTimerTestView *)lpArg;
	// 创建等待定时器
	pView->m_hTimer = CreateWaitableTimer(NULL, FALSE, _T("MyWaitableTimer"));// 自动归零
	if (NULL == pView->m_hTimer)
	{
		AfxMessageBox(_T("Can't create waitable timer!"));
		return;
	}
	LARGE_INTEGER liDueTime;
	liDueTime.QuadPart = -2000000LL;// 200ms=200*10^6ns=2*10^6(100ns)

	// 设置等待定时器
	if (FALSE == SetWaitableTimer(pView->m_hTimer, &liDueTime, 200, NULL, NULL, FALSE))
	{
		AfxMessageBox(_T("SetWaitableTimer Failed!"));
		return;
	}
	while (pView->m_bTimerThreadRun)
	{
		if (WaitForSingleObject(pView->m_hTimer, INFINITE) != WAIT_OBJECT_0)
		{
			pView->MessageBox("WaitForSingleObject failed ");
		}
		else
		{
			pView->data++;
		}
	}
	CancelWaitableTimer(pView->m_hTimer);
	CloseHandle(pView->m_hTimer);

	return;
}
        (2)另外一种是,多线程+WaitableTimer实现定时器功能(使用响应函数的方法),相关代码如下:

// 定时器线程执行函数
void TimerThreadProc(LPVOID lpArg)
{
	// 多线程+WaitableTimer实现定时器功能(使用定时响应函数版本)
	CWaitableTimerTestView *pView = (CWaitableTimerTestView *)lpArg;
	// 创建等待定时器
	pView->m_hTimer = CreateWaitableTimer(NULL, FALSE, _T("MyWaitableTimer"));// 自动归零
	if (NULL == pView->m_hTimer)
	{
		AfxMessageBox(_T("Can't create waitable timer!"));
		return ;
	}
	LARGE_INTEGER liDueTime;
	liDueTime.QuadPart = -2000000LL;// 200ms=200*10^6ns=2*10^6(100ns)
	
	while (pView->m_bTimerThreadRun)
	{
		// 设置等待定时器
		if (FALSE == SetWaitableTimer(pView->m_hTimer, &liDueTime, 200, (PTIMERAPCROUTINE)TimerAPCProc, (LPVOID)lpArg, FALSE))
		{
			AfxMessageBox(_T("SetWaitableTimer Failed!"));
			return;
		}
		else// 如果没有,就不会调用TimerAPCProc
		{
			SleepEx(
				INFINITE,     // Wait forever
				TRUE);       // Put thread in an alertable state
		}
	}
	CancelWaitableTimer(pView->m_hTimer);
	CloseHandle(pView->m_hTimer);
	return;
}
// 远程调用
VOID CALLBACK TimerAPCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
	CWaitableTimerTestView *pView = (CWaitableTimerTestView*)lpArg;
	if (WaitForSingleObject(pView->m_hTimer, INFINITE) != WAIT_OBJECT_0)
	{
		pView->MessageBox("WaitForSingleObject failed ");
	}
	else
	{
		pView->data++;
	}
}

        3.多线程+Sleep延时函数:(与2类似)

           另一个线程一直运行,每个一定时间运行一次,Sleep(mSec);

           注意此种方式在调用OnDraw(GetDC)方法时,会出现pDoc重复获取的assert不合法、闪烁及绘制错误等问题

// 定时器线程执行函数
void TimerThreadProc(LPVOID lpArg)
{
	// 多线程+Sleep(msec)实现定时器功能
	CWaitableTimerTestView *pView = (CWaitableTimerTestView *)lpArg;
	while (pView->m_bTimerThreadRun)
	{
		pView->data++;
		Sleep(200);
	}
}

        4.采用多线程+WM_TIMER消息混合方式:

           多线程固定时间计算各图像元素的位置,而WM_TIMER通知定时绘图显示,在WM_KEYDOWN消息频繁时,由于WM_KEYDOWN处理过程中也要采用OnDraw方法重绘整个屏幕,故也可以达到定时移动背景和敌机相关的定时移动。
5.采用多媒体定时器,更加精确。(还未深入研究过)

        6.DirectX中的定时器(还未深入研究过)

以上是我目前为止查到能在MFC中使用的定时器方式,欢迎大家讨论补充,互相学习,共同进步!


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
01-22 2893
在 C# 中,你可以使用以下几种方法来实现定时器功能: 1. System.Timers.Timer:这是一个基于线程定时器,可以在指定的时间间隔内重复执行指定的代码。你可以设置 Interval 属性来指定时间间隔,并通过 Elapsed 事件来处理计时器事件。 ```csharp using System; using System.Timers; public class TimerExample { private static Timer timer; public static void Main() { timer = new Timer(); timer.Interval = 1000; // 设置时间间隔为1秒 timer.Elapsed += TimerElapsed; // 绑定事件处理程序 timer.Enabled = true; // 启动计时器 Console.WriteLine("Press Enter to stop the timer."); Console.ReadLine(); timer.Enabled = false; // 停止计时器 } private static void TimerElapsed(object sender, ElapsedEventArgs e) { Console.WriteLine("Timer elapsed at {0}", e.SignalTime); } } ``` 2. System.Threading.Timer:这是一个基于线程池的定时器,也可以在指定的时间间隔内重复执行指定的代码。你可以使用 Change 方法来设置时间间隔,并通过 TimerCallback 委托来处理计时器事件。 ```csharp using System; using System.Threading; public class TimerExample { private static Timer timer; public static void Main() { TimerCallback callback = new TimerCallback(TimerElapsed); timer = new Timer(callback, null, 0, 1000); // 设置时间间隔为1秒 Console.WriteLine("Press Enter to stop the timer."); Console.ReadLine(); timer.Dispose(); // 停止计时器 } private static void TimerElapsed(object state) { Console.WriteLine("Timer elapsed at {0}", DateTime.Now); } } ``` 3. System.Threading.Tasks.Task.Delay:这是一种基于异步任务的延迟执行方法,可以在指定的时间间隔后执行指定的代码。 ```csharp using System; using System.Threading.Tasks; public class TimerExample { public static async Task Main() { Console.WriteLine("Press Enter to start the timer."); Console.ReadLine(); while (true) { Console.WriteLine("Timer elapsed at {0}", DateTime.Now); await Task.Delay(1000); // 设置时间间隔为1秒 } } } ``` 这些是在 C# 中实现定时器功能的几种常用方法。你可以根据自己的需求选择适合的方法来实现定时器功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值