OnIdle的调用

OnIdle的调用

首先看GetMessagePumpMessage中被调用)与PeekMessage的区别:

当消息队列为空时,程序会被阻塞在GetMessage的调用处。这时系统就有会去照顾其它进程了。而PeekMessage不会挂起,而是耗掉系统分配给它的时间片。

 

Run函数中要解决的问题是,在消息队列为空的时间调用OnIdle方法干一些私事,但最好不会太影响别人。

怎么调用OnIdle呢?若消息队列一为空就调用OnIdle的话,就像在做死循环,系统将会卡死。因为消息队列为空的机会是很多的。最理想的做法应该是:当消息队列为空时,刚开始时(头几次循环用LONG lIdleCount控制)进行必要的调用OnIdle,之后让进程堵在GetMeessage处,以让出CPU时间片。

这样做还是有点不妥,为啥呢?再看看上面的想法:当消息队列一空,先调用OnIdle,再进入GetMessage堵在那。一旦有消息来了,GetMessage不堵了,又得开始忙乎了,一来要处理队列中的消息,二来是等消息处理完后进入OnIdle。如比系统安装了个定时器,麻烦就来了。每次WM_TIMER来的时候都会打破程序的堵塞。现在的任务有点像是要避免进入OnIdle,谁叫它太贫了呢?

改进方案是,不是让所有的消息在处理完后都进行OnIdle调用,看情况。可以用一个变量(代码中用BOOL bIdle)标识一下,可以通过IsIdleMessage(虚函数)判断消息它是否需要调用OnIdle的。在调用OnIdle之前,先看看这个标识变量,判断是否进入。IsIdleMessage可以被重载,用户可以对WM_TIMER等消息进行自定义的筛选,只要不想进入OnIdle就返回FALSE

int CWinThread::Run() { ASSERT_VALID(this); _AFX_THREAD_STATE* pState = AfxGetThreadState(); BOOL bIdle = TRUE; LONG lIdleCount = 0; for (;;) { // 第一个阶段,空闲时调用OnIdle,干一些“私事”但消耗时间片 while (bIdle && !::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE)) { if (!OnIdle(lIdleCount++)) bIdle = FALSE; // assume "no idle" state } // 第二个阶段:处理消息,也许会堵在那,把时间片让给别人 do { if (!PumpMessage()) return ExitInstance(); if (IsIdleMessage(&(pState->m_msgCur))) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE)); } }

你可能感兴趣的:(thread,timer,null,任务)