【MFC多线程】多线程里面WM_TIMER消息的响应
在项目中遇到的一系列用 VC多线程问题 总目录贴: (先留着 以后填上)写在前面话:
该问题是我近期在实际上位机程序项目中遇到的,我把该问题重点提取出来,并且附上我自己的理解和解决思路。
特此记录下来为以后查阅起来做参考。
开发环境VC6.0SP6
运行环境XP SP3
问题描述:
一个基于对话框的程序:
下面是我的主要代码:
void CExample2Dlg::OnButton1()
{
// TODO: Add your control notification handler code here3
sum =0;
uiTimer = SetTimer(1,10,NULL);
AfxBeginThread(MyThread1,this);
}
UINT CExample2Dlg::MyThread1(void *param)
{
CExample2Dlg *Dlg=(CExample2Dlg *)param;
Sleep(105);
CString tmp;
tmp.Format("%d",Dlg->sum);
AfxMessageBox(tmp);
return 0;
}
void CExample2Dlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
sum++;
CDialog::OnTimer(nIDEvent);
}
目的就是在按钮Button1点下过后,就开起定时器,在OnTimer里面做计数,再开启线程,然后在线程里面Sleep(105),然后再用AfxMessageBox(tmp);的方式显示出在Sleep(105)这段时间里面到底响应了多少次OnTimer;
我这里定时器周期设置的是10ms,我在线程里面Sleep(105),按照道理说,应该响应10次OnTimer,但是实际情况确是只响应了6,7次 这个次数不定 我想问问为什么?
我认为以上原因可能是启动线程需要一定时间,至于什么时候启动可能是操作系统自己分配的,
那么我把上面代码变一下,变成我在线程里面启动定时器,就不存在启动线程需要的时间干扰了吧
void CExample2Dlg::OnButton1()
{
// TODO: Add your control notification handler code here3
AfxBeginThread(MyThread1,this);
}
UINT CExample2Dlg::MyThread1(void *param)
{
CExample2Dlg *Dlg=(CExample2Dlg *)param;
Dlg->start();
Sleep(110);
CString tmp;
tmp.Format("%d",Dlg->sum);
AfxMessageBox(tmp);
return 0;
}
void CExample2Dlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
sum++;
CDialog::OnTimer(nIDEvent);
}
void CExample2Dlg::start()
{
sum =0;
uiTimer = SetTimer(1,10,NULL);
}
问题提出:
整个流程就是点击botton 就启动线程 然后线程里面启动定时器,然后线程sleep,让OnTimer响应,等线程Sleep完了,再输出响应了多少次OnTimer,可是这样 也就显示响应了7次,按理说,应该响应10次的,这是为什么?
问题分析以及解决
根据MSDN上面的解释,可以找到以下文字:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx
The time-out value, in milliseconds.
If uElapse is less than USER_TIMER_MINIMUM (0x0000000A), the timeout is set to USER_TIMER_MINIMUM. If uElapse is greater than USER_TIMER_MAXIMUM (0x7FFFFFFF), the timeout is set to USER_TIMER_MAXIMUM.
Timer使用的时间中断,
Windows中每隔1/18秒触发一个时钟中断,所以,Timer的定时精度1000/18
SetTimer线程优先级别很低,要等其它的线程执行完后运行它,所以精度度很差,用于要求不高的场合。如果要求高的话可以采用多媒体定时或更高级别的定时方法。
WM_TIMER消息的优先级比较低,当消息队列里没有其它待处理的高优先级的消息的时候,才会去处理它,如果你的应用程序很繁忙,那么延迟就会很明显。
The WM_TIMER message is a low-priority message. The GetMessage and PeekMessage functions post this message only when no other higher-priority messages are in the thread's message queue.
可以用以下代码验证:
#include <windows.h>
static int g_nCount = 0;
#define Timer_Once_Time (1000/18)
DWORD WINAPI threadFunc (LPVOID pArg)
{
Sleep(100*Timer_Once_Time);
printf("%d",*((int*)pArg));
return 0;
}
void CALLBACK TimerProc(HWND hwnd, UINT message, UINT timerID, DWORD time)
{
g_nCount++;
printf("%d\n",g_nCount);
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread;
hThread = CreateThread (NULL, 0, threadFunc, &g_nCount, 0, NULL );
SetTimer(NULL, 0, 10*Timer_Once_Time, TimerProc);
// 主消息循环:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
//if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
用时间戳最好,每次获取当前时间与时间戳比较
精度有各种选择,和选择的机制和数据类型有关
可以做到ms甚至ns级的定时 周鹏 发表于 2015-6-16 15:11
用时间戳最好,每次获取当前时间与时间戳比较
精度有各种选择,和选择的机制和数据类型有关
时间戳 是什么东西哟?我没见过也。。。
我为了更精确的定时,往往采用优先级高的定时器,只不过这次没有用到, 也解决了,用户要求没有这么高。。
页:
[1]