hThreadl1=CreateThread(NULL,0,Dlg1thread1,NULL,0,NULL);DWORD WINAPI Dlg1thread1(LPVOID lpParameter)
{
while(Thread1==0)
{
buffer[]=readdata();
Sleep(20);
}
return 0;
}我开辟一个线程读取外部设备的数据,保存在全局变量数组中,主线程的定时器中处理数据,将数据显示到对话框上,现在运行发现线程一创建,能够马上读出数据上来,但是CPU使用90%以上,再改变外部设备中数据后,数据要很长时间才能读上来,看了一篇帖子说线程函数中死循环中加了Sleep不会让CPU使用一直很高,怎么了用了Sleep也不行,刚用到多线程,可能问的比较弱智,请见谅。
{
while(Thread1==0)
{
buffer[]=readdata();
Sleep(20);
}
return 0;
}我开辟一个线程读取外部设备的数据,保存在全局变量数组中,主线程的定时器中处理数据,将数据显示到对话框上,现在运行发现线程一创建,能够马上读出数据上来,但是CPU使用90%以上,再改变外部设备中数据后,数据要很长时间才能读上来,看了一篇帖子说线程函数中死循环中加了Sleep不会让CPU使用一直很高,怎么了用了Sleep也不行,刚用到多线程,可能问的比较弱智,请见谅。
解决方案 »
- extern 的疑惑....
- 关于listview,listctrl,virtuallist的问题之一
- 如何用非MFC方式(GDI+FONT)显示一个旋转45度的字句?
- 谁扣的我6分信誉分,给我解释一下,我散分管你P事!
- 如何得到显示器驱动?
- 系统托盘POPup-menu,鼠标不在menu上点,她不关闭,帮帮忙!!!!!!!
- 一个初学者的关于类型转换的问题
- 网页java中c++实现oracle登陆 和增删改查语句[email protected]
- 请教各位大虾,在API函数 CreateFont() 中怎么指定字体呀?
- vs2008 ActiceX控件问题
- ATL程序中,WNetAddConnection2建立远程连接,报错!
- 在VS2008下使用AxtiveX控件
你应该设置一个事件或者信号量之类的来控制。当data数据改变(即需要线程读取数据时buffer[]=readdata();)时,使信号受信。
我这里写个使用事件的范例,具体的你可以百度一下
HANDLE hEvent = CreateEvent();;BOOL IsDataModify() //数据改变
{
SetEvent(hEvent);
return TRUE;
}DWORD WINAPI Dlg1thread1(LPVOID lpParameter)
{
while(Thread1==0)
{
waitforsingleobject(hEvent);
buffer[]=readdata();
}
return 0;
}
============================
是比较长,测试过,需要1秒。如果不用多线程,在主线程中再开一个定时器,将读取数据的部分放在其中,就是在主线程中用一个定时器读取数据,一个定时器处理数据,cpu的使用在30%和2%之间跳动,读取的数据3秒左右刷新一次,但是键盘敲击和鼠标点击的动作响应变得很慢。
不用多线程,在主对话框中开一定时器,里面只放readdata(),CPU使用4%。定时器里只放数据处理的部分,就是从数组中取数,然后转换一下输出到编辑框中,这部分测试过应该不花10ms,但只测这部分,cpu使用95%以上。定时器中放以上两部分,cpu使用4%-40%之间跳跃。
这是怎么回事?现在开一个线程,不开定时器,线程函数中只放readdate(),cpu使用4%。现在开一个线程,开一个定时器(主线程中),线程函数中只放readdate(),定时器中放上面的数据处理部分,CPU使用98%
谁帮忙分析下这一问题,谢谢。
{
....
sleep(...);
}
这种形式的线程占CPU是很大的
比如:HANDLE hEvent = CreateEvent();;void dataMoniter() 监控数据
{
........;
SetEvent(hEvent);
}DWORD WINAPI Dlg1thread1(LPVOID lpParameter)
{
while(Thread1==0)
{
WaitforSingleobject(hEvent,timeout);
buffer[]=readdata();
}
return 0;
}
这样当没有数据的时候,任务会被侧地挂起,
交出时间片
{
if(nIDEvent==2)
{
//***********************************display link_flower_cur
pwnd=GetDlgItem(IDC_EDIT2);
if(GetFocus()==pwnd)//判断焦点在不在IDC_EDIT2上
{
if(mInsertFlag==1)//如果键盘Insert按下,即要通过该编辑框输入数据,然后写进设备中
{
if(mDlg3FlagEdit2==0)//该编辑框未进入数据改写状态
{
SetDlgItemText(IDC_EDIT2,_T(""));//当要改写数据时,将编辑框为空
}
mDlg3FlagEdit2=1;//该编辑框进入数据改写状态
}
} if (mDlg3FlagEdit2==0)//该编辑框未进入数据改写状态
{
unsigned int link_flower_cur_SAVE=combine2(bufferDB2[116],bufferDB2[117]);
int link_flower_cur_SAVE_temp=link_flower_cur_SAVE;
strDB.Format(_T("%d"),link_flower_cur_SAVE_temp);
SetDlgItemText(IDC_EDIT2,strDB);
}
//***********************************display link_flower_cur
////对于每个编辑框都有这样一个模块,后面还有60个这样的模块
}
CDialog::OnTimer(nIDEvent);
}
void CDialog3::OnEnKillfocusEdit2()
{
if(mInsertFlag==1)
{
KillTimer(2);
mInsertFlag=0;//将键盘Insert键按下的标志位复位
mDlg3FlagEdit2=0;//将编辑框2进入改写状态的标志位复位
CString stra;
int a;
GetDlgItemText(IDC_EDIT2,stra);//获取通过键盘输入的值
a=_ttoi(stra);
unsigned char b[4];
*(int *)b=a; unsigned char c[2];//**********************
c[0]=b[0];
c[1]=b[1]; unsigned int d=combine2(c[0],c[1]);//做了数据格式变换,满足外部设备中数据存储形式要求
//SuspendThread(hThreadl1);
WriteData(2,116,2,&d);//向编辑框2对应的设备中地址写入通过键盘输入想写进去的值
//ResumeThread(hThreadl1);
SetTimer(2,Dlg3times,NULL);
}
}
另外OnChar中做了键盘“Insert”按下后,mInsertFlag=1;创建线程的地方,定时器第一次开启的时候也使用的SetTimer(2,Dlg3times,NULL);其中Dlg3times取10,20,100都试过。
你的读取数据的线程waitsingleobject一直等待这个事件被通知,然后再取数据。
waitsingleobject没有返回之前,这个线程是不会不被调度到的,自然也就不占cpu。
在子线程中读取数据,如果获得了数据,就发送自定义消息给主线程,消息函数中将数据显示出来,结果外部设备中数据变化后,数据显示能很快刷新,这证明子线程中不断读取数据的工作和消息响应函数中显示数据的工作都是正常的。现在在某一Edit2改写数据,在其OnEnKillfocusEdit2中写数据进设备,在设备上观测到写数据正确,并且速度很快,但是这以后,整个界面上的Edit要过1分钟左右才刷新,应该是OnEnKillfocusEdit2执行后约1分钟后子线程才开始读数据,这是什么原因?如果把显示数据的部分放到定时器中,现象和上面一样。
如果把读数据的部分和显示数据的部分都放到定时器中,通过Edit写数据进设备后,Edit过3秒左右能刷新成写进去的值,这个速度还是比较快的,但是整个界面用Tab键移焦点,在Edit中敲数字这两项工作很慢很慢,就好像CPU的精力都用在了读数据和显示数据上来,没精力接受键盘的按键消息。难道是定时器的优先级比较高,而建立的子线程的优先级比较低,当OnEnKillfocusEdit2执行完后很久才轮到子线程执行?我试过用AfxBeginThread创建各种优先级别的子线程,但是效果还是改写数据后很久Edit中的数据才刷新。
请教高手啊
Try this:DWORD WINAPI Dlg1thread1(LPVOID lpParameter)
{
HANDLE hEvent; hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
while(Thread1 == 0) {
buffer[] = readdata();
::WaitForSingleObject(hEvent, 20);
}
::CloseHandle(hEvent); return 0;
}
至于你的线程内部用Thread1这种标志的方法去控制是否退出线程循环,不建议这么做。
然后发消息到主线程,通知数据已更新,同时要做好共享数据保护,防止两个线程同时访问!少用定时器,定时器也是比较消耗资源的!同时你提到写数据时间长的问题,不知道你是如何写,通过什么机制?您觉得以现在机器配制,你这么点数据能用到这么高的CPU使用率?这么高的CPU使用率说明你有线程长时间占用了CPU!您可以试在读线程中设置一个事件,用来写数据,也可以另开一个线程专门写数据!
现在我发现大家对我的情况理解有误,我想再次描述下
非模态对话框上有一些Edit,一方面用来显示外设中对应地址的数据,一方面要能够实现通过键盘输入改写外设中对应地址的数据。整个代码有三部分,一部分是通过ReadData()读取外设数据的部分,这部分无论放到哪里都要花费约1秒执行一次,因为要把界面监控的所有数据一起读上来。第二部分是将数据显示到Edit上,这部分显然花费的时间非常少。第三部分则是每个Edit在用户通过键盘输入数字后,要把数字写进外部设备中对应的地址,这第三部分我是放在每个Edit的OnEnKillfocusEdit中的,向设备中写一个数据用WriteData,需要约110ms,当然,如果通过编辑框改写了数据,这时编辑框上显示的数据应该马上刷新成改写后的各个数据。
现在现象是
(1)不开子线程,将第一部分和第二部分都放到定时器中,外设中的数据通过外部改变后,Edit中的显示能马上刷新,当通过Edit改写数据后写进外设,约2秒后,Edit能刷新成改后的值,这都是比较理想的,但是在Edit中敲数据的时候和按Tab键时,响应很慢,敲一个数字,过了好几秒钟Edit上才显示敲的数据,同时CPU很奇怪的在4%和30%间跳跃。
(2)开子线程,将第一部分放到子线程,读到数据后就给对话框发送消息,将第二部分放到消息响应函数中。外设中的数据通过外部改变后,Edit中的显示能马上刷新,CPU使用2%左右,程序对键盘响应迟钝的现象没有。但是当通过Edit改写数据后写进外设,Edit要经过约1分钟才能刷新成改写后的值,这是难以忍受的。这里仔细观察,数据早就写进了外设中,只不过好像过了好久,子线程中读数据才开始执行,等待Edit刷新期间,cpu使用0%,就好像不工作死了样,约1分钟后,CPU使用2%-4%
(3)将(2)中的数据显示放到主线程的定时器中,CPU使用100%,其它现象和(2)一样。
1、数据缓冲区。子线程要往里放从设备中读出的数据,主线程要用它来刷新显示。不过这个问题好解决:只要子线程用SendMessage而不是PostMessage给主线程发消息即可,无须采取其它措施。顺便说一句,你子线程中的Sleep应该删掉。既然你的设备读取需要1秒钟,那么再用Sleep来给CPU减压毫无必要。
2、设备总线。你的子线程在不断地读设备,而你在往设备里写数据的时候,是用主线程写的吧?你的设备是什么、是否支持同时读写我不清楚,但既然你说单线程时没有停一分钟的问题,那么最大的可能就是:你的设备总线在遇到写指令的时候,会把当前正在执行的读指令阻塞、或者中断(readdata既然要一分钟,那么你每次写的时候都几乎必然会遇到一个readdata正在执行当中)。而你的readdata在迟迟没有接到数据的情况下会以失败告终,那个1分钟其实就是Timeout。当然,你的设备并没有停止响应,当它写完以后,你用别的方法(另一个程序或者线程)再去读它,它仍然能很好地读出来,只不过在写指令之前的那个读指令被它Cancel了而已。
WriteData(*,testa);//将testa写进外设地址*中
ReadData(*,testb);//将外设地址*中的数据读上来存到变量testb中
str.Format(_T("%d"),testb);
SetDlgItmText(IDC_EDIT2,str);
点击按钮后,约0.2秒后EDIT2上刷新成testa。这说明写一个数下去后,紧接着读数据上来,能狗得到写下去时候的数据。那我现在就不明白,读数据的部分放到子线程中,这里读的数据多了,也就是有0.1秒变成了1秒,显示数据部分放到消息响应函数中,怎么就要1分钟才能数据刷新。就算是写完数据后,子线程才开始创建,然后稳定,然后读几百个数据上来,应该也只是2,3秒时间啊,怎么会拖到1分钟呢?
当你在界面(主线程)的编辑框中更改数据的时候,你的子线程是在不停地循环读取数据吧?当你界面上某个编辑框失去焦点的时候,你的主线程会向设备写入数据,这没错吧?由于你的子线程是不停地循环读数据的,因此,不论你读一个数据需要1秒、0.1秒、甚至0.0001秒,当你主线程对设备发出“写入数据”的指令的那个瞬间,你的子线程都一定是在读某个数据的过程中(因为你的子线程除了读数据之外不干别的了,如果那个瞬间不是在读数据的话,那你说它在干什么?)。好,假定你的子线程在第10秒的时候发出了一个读指令,根据你的说法,本来在第10.1秒的时候数据就返回来了,但问题是:你的主线程在第10.05秒的时候发出了一个写指令,而你的设备的响应方式是:假若在前一指令没执行完的时候又接到一条新指令,则放弃前一条指令。于是,当在第10.05秒设备接到你的写指令的时候,设备会放弃还没有完成的那条读指令,转而执行这条新的写指令。于是,你的主线程会在第10.15秒的时候写入成功而返回,并且设备也处于空闲状态了。但你的子线程却不知道这一切,它知道的仅仅是:设备一直没有把数据返回来,于是它就等啊等啊,直到等得实在不耐烦了(你的那些readdata、writedata之类的函数,内部肯定会有timeout方面的设置,如果过多长时间设备没有响应的话,就算操作失败),它才会以失败告终,而这个让它“等得不耐烦”的时间,恐怕就是1分钟。于是1分钟之后,本次读取操作失败,readdata函数返回,你的子线程继续运行,继续对设备发出读指令,并顺利读出,一切都又正常了。
那么,如果在写数据完成后,想办法让子线程中的ReadData重新开始执行,而不是做等待返回值的工作,就不会出现写数据后1分钟显示数据才刷新的问题了。那么这个怎么做呢,我试过在写数据的时候用
SuspendThread(hThreadl1);
ResumeThread(hThreadl1);
无论是WriteData之前调用还是之后调用SuspendThread(hThreadl1),情况都没有改变,现在发现应该是线程挂起时线程函数在等待读数据的返回,结束挂起时还是在等待读数据的返回。有什么办法在OnEnKillfocusEdit中写数据后让线程函数从头开始执行而不是从挂起时的位置开始执行呢?