基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,用多线程解决如何还是没效果
基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,用多线程解决怎么还是没效果?
前两天曾经发过贴,请教如何解决界面切换困难的问题,听了一些朋友的建议,决定采用多线程解决,可是发现还是没效果,我把问题简单描述一下,请各位看客帮忙参谋参谋,多提宝贵意见。
在一个基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,后来发现是一个数据采集函数太耗时了,该函数执行完大约需要2~3秒。而且该函数还要每隔大约3秒钟就要被调用一次。后来我决定将该函数放到一个线程函数中执行,该函数执行完再将结果赋给一个全局的结构体数组。然后在主线程中用虚拟列表将保存在结构体数组中的数据显示到列表中。思路大致就是这样的,代码大致如下:
//原来的方案:
void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}
void CPidHistgramView::ReceiveData()
{
for(int i=0;i<m_listCount;i++)
{
//调用库中函数获取数据,耗时约3秒
.....
.....
////
//将得到的数据赋给全局结构体数组
strcpy( g_data[i].str1,sValue1);
strcpy( g_data[i].str2,sValue2);
...
strcpy( g_data[i].str8,sValue8);
}
}
因为数据采集函数太耗时,所以将其放入到工作线程中,后来的采用方案在工作线程中建立一个消息队列,获取工作线程的WM_TIMER消息,每3秒发送一次。在工作线程的WM_TIMER响应函数里再调用全局函数ReceiveData()采集数据,代码大致如下:
// 线程函数,在OnInitialUpdate()函数中调用 AfxBeginThread(ThreadFunc,(LPVOID)NULL)启动
UINT ThreadFunc(LPVOID lParam)
{
int nTimerID=SetTimer(NULL,0,3000,NULL); // 设定一个3秒间隔的定时器
MSG msg;
PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
DWORD dEndWord;
BOOL bRun=TRUE;
while (bRun)
{
dEndWord=WaitForSingleObject(eventEnd,0); //查询"结束事件"状态,立即返回
if(dEndWord==WAIT_OBJECT_0) //可以正常退出
{
KillTimer(NULL,nTimerID);
return 0;
}
if (GetMessage(&msg,NULL,NULL,NULL))
{
switch(msg.message)
{
case WM_TIMER:
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒 }
break;
default:
break;
}
}
}
return 0;
}
void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}
主要代码如上所示,主要思路是程序运行时就启动工作线程,工作线程每3秒发送一个定时器消息,ReceiveData()采集函数大约要费时2秒多。ProcessData()函数每3秒被调用一次,用来刷新界面上的列表控件,显示时用到了CVirtualList Control 技术。
按照原来的设想,将采集函数放到工作线程后CPU应该会降下来,不会再阻塞主线程,可是运行发现,CPU的占有率还是很高,达到90%以上,调试发现主要问题出在ReceiveData()这个采集函数上,当把这个函数注销后,CPU就很低了。而且用虚拟列表显示时按说应该每调用一次,界面就一次完整的把数据显示出来,可现在发现,当每3秒调用ProcessData()函数刷新界面时,列表有时是由上到下一行一行显示数据,效果非常差,搞不清楚用了虚表怎么还会这样,难道是因为CPU太忙碌了的缘故?
像我这种情况该怎么解决?
------解决方案--------------------
在ReceiveData里面的循环体里面简单加一句Sleep(10);吧
------解决方案--------------------
CPU使用率高,说明你的程序执行的操作需要占用大量的CPU时间,利用多线程和设置线程优先级或者适当Sleep可以改善界面响应,但无法降低CPU使用率。这种情况只能从优化原理和优化代码方面来设法缓解了,如果无法缓解,并且CPU的空闲率为0%,就需要提高软件运行环境的要求了。
------解决方案--------------------
这种问题我也遇到过,Sleep只能稍微缓解CPU的高占用,而且会导致处理效率的降低。
这种情况,必须优化你的接收处理过程ReceiveData,处理数据要比接收数据耗时的多,一定要优化数据处理的算法。
------解决方案--------------------
数据采集放到单独线程中,可以加上延时函数,我一般是插入以下函数,会明显改善显示停顿问题:
前两天曾经发过贴,请教如何解决界面切换困难的问题,听了一些朋友的建议,决定采用多线程解决,可是发现还是没效果,我把问题简单描述一下,请各位看客帮忙参谋参谋,多提宝贵意见。
在一个基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,后来发现是一个数据采集函数太耗时了,该函数执行完大约需要2~3秒。而且该函数还要每隔大约3秒钟就要被调用一次。后来我决定将该函数放到一个线程函数中执行,该函数执行完再将结果赋给一个全局的结构体数组。然后在主线程中用虚拟列表将保存在结构体数组中的数据显示到列表中。思路大致就是这样的,代码大致如下:
//原来的方案:
void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}
void CPidHistgramView::ReceiveData()
{
for(int i=0;i<m_listCount;i++)
{
//调用库中函数获取数据,耗时约3秒
.....
.....
////
//将得到的数据赋给全局结构体数组
strcpy( g_data[i].str1,sValue1);
strcpy( g_data[i].str2,sValue2);
...
strcpy( g_data[i].str8,sValue8);
}
}
因为数据采集函数太耗时,所以将其放入到工作线程中,后来的采用方案在工作线程中建立一个消息队列,获取工作线程的WM_TIMER消息,每3秒发送一次。在工作线程的WM_TIMER响应函数里再调用全局函数ReceiveData()采集数据,代码大致如下:
// 线程函数,在OnInitialUpdate()函数中调用 AfxBeginThread(ThreadFunc,(LPVOID)NULL)启动
UINT ThreadFunc(LPVOID lParam)
{
int nTimerID=SetTimer(NULL,0,3000,NULL); // 设定一个3秒间隔的定时器
MSG msg;
PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
DWORD dEndWord;
BOOL bRun=TRUE;
while (bRun)
{
dEndWord=WaitForSingleObject(eventEnd,0); //查询"结束事件"状态,立即返回
if(dEndWord==WAIT_OBJECT_0) //可以正常退出
{
KillTimer(NULL,nTimerID);
return 0;
}
if (GetMessage(&msg,NULL,NULL,NULL))
{
switch(msg.message)
{
case WM_TIMER:
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒 }
break;
default:
break;
}
}
}
return 0;
}
void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}
主要代码如上所示,主要思路是程序运行时就启动工作线程,工作线程每3秒发送一个定时器消息,ReceiveData()采集函数大约要费时2秒多。ProcessData()函数每3秒被调用一次,用来刷新界面上的列表控件,显示时用到了CVirtualList Control 技术。
按照原来的设想,将采集函数放到工作线程后CPU应该会降下来,不会再阻塞主线程,可是运行发现,CPU的占有率还是很高,达到90%以上,调试发现主要问题出在ReceiveData()这个采集函数上,当把这个函数注销后,CPU就很低了。而且用虚拟列表显示时按说应该每调用一次,界面就一次完整的把数据显示出来,可现在发现,当每3秒调用ProcessData()函数刷新界面时,列表有时是由上到下一行一行显示数据,效果非常差,搞不清楚用了虚表怎么还会这样,难道是因为CPU太忙碌了的缘故?
像我这种情况该怎么解决?
------解决方案--------------------
在ReceiveData里面的循环体里面简单加一句Sleep(10);吧
------解决方案--------------------
CPU使用率高,说明你的程序执行的操作需要占用大量的CPU时间,利用多线程和设置线程优先级或者适当Sleep可以改善界面响应,但无法降低CPU使用率。这种情况只能从优化原理和优化代码方面来设法缓解了,如果无法缓解,并且CPU的空闲率为0%,就需要提高软件运行环境的要求了。
------解决方案--------------------
这种问题我也遇到过,Sleep只能稍微缓解CPU的高占用,而且会导致处理效率的降低。
这种情况,必须优化你的接收处理过程ReceiveData,处理数据要比接收数据耗时的多,一定要优化数据处理的算法。
------解决方案--------------------
数据采集放到单独线程中,可以加上延时函数,我一般是插入以下函数,会明显改善显示停顿问题:
- C/C++ code
void _Sleep( INT iMS ) { DWORD dwStart = GetTickCount() ; while( TRUE ) { MSG msg; while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) { ::TranslateMessage( &msg ); ::DispatchMessage( &msg ); } if ( GetTickCount() - dwStart > (DWORD)iMS ) { break ; } } }