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也不行,刚用到多线程,可能问的比较弱智,请见谅。

解决方案 »

  1.   

    readdata(),只能从这个函数入手了
      

  2.   

    SetThreadPriority 把线程的优先级 改低点 试试。。
      

  3.   

    多线程最好不要这样子实现。做个死循环这不是在你控制之外么。
    你应该设置一个事件或者信号量之类的来控制。当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;
    }
      

  4.   

    我也是用Sleep,不过处理的是数据库,CPU才占用不到20%呀。读的文件大的话,一般要用异步读的,同步很浪费CPU时间的,可能是你readdata()耗的时间太长了吧。
      

  5.   

    可能是你readdata()耗的时间太长了吧。
    ============================
    是比较长,测试过,需要1秒。如果不用多线程,在主线程中再开一个定时器,将读取数据的部分放在其中,就是在主线程中用一个定时器读取数据,一个定时器处理数据,cpu的使用在30%和2%之间跳动,读取的数据3秒左右刷新一次,但是键盘敲击和鼠标点击的动作响应变得很慢。
      

  6.   

    如果这样行的话,改成waitable timer 内核对象在多线程中定时试试,界面就不会卡了,而且WM_TIMER优先级低,界面操作频繁的话,就有可能丢失了
      

  7.   

    刚刚测试了下,
    不用多线程,在主对话框中开一定时器,里面只放readdata(),CPU使用4%。定时器里只放数据处理的部分,就是从数组中取数,然后转换一下输出到编辑框中,这部分测试过应该不花10ms,但只测这部分,cpu使用95%以上。定时器中放以上两部分,cpu使用4%-40%之间跳跃。
    这是怎么回事?现在开一个线程,不开定时器,线程函数中只放readdate(),cpu使用4%。现在开一个线程,开一个定时器(主线程中),线程函数中只放readdate(),定时器中放上面的数据处理部分,CPU使用98%
    谁帮忙分析下这一问题,谢谢。
      

  8.   

    谁能帮忙解释下一段花费十毫秒不到的程序,只是将获取到的数据显示到对话框上,怎么会占那么多CPU资源。
      

  9.   

    建议注销buffer[]=readdata();这行测试,就能知道是线程问题还是读数据问题,个人感觉应该是读数据问题,
      

  10.   

    我发现了造成CPU大大被占用的原因是定时器中使用了较多的SetDlgItemText。屏闭掉就能发现CPU使用正常。看来不是创建的线程有问题,而是主线程的问题。谁能帮忙解释下这里的主线程阻塞是什么原因造成的?就是上面那条语句的问题,还是开的定时器默认的优先级很高,本来就会让主现程阻塞?
      

  11.   

    不清楚你的readdata()函数里做了什么
      

  12.   

    取消定时器 用线程试试 另外SetDlgItemText 用到的地方看看可以优化不。
      

  13.   

    while()
    {
    ....
    sleep(...);
    }
    这种形式的线程占CPU是很大的
      

  14.   

    SetDlgItemText 用到的地方怎么优化啊?要把数据显示到编辑框中,不用这个就只能把编辑框添加变量,然后用UpDate(False)来显示数据了,试过了,CPU使用正常,线程函数里读数据的代码很久才能刷新数据,应该还是主线程阻塞了,
      

  15.   

    多线程最好不要用sleep之类的做阻塞,而是应该设置事件或者信号量之类的来控制。
    比如:HANDLE hEvent = CreateEvent();;void dataMoniter() 监控数据
    {
        ........;
        SetEvent(hEvent);
    }DWORD WINAPI Dlg1thread1(LPVOID lpParameter)
    {
      while(Thread1==0)
     {
       WaitforSingleobject(hEvent,timeout);
       buffer[]=readdata();
     }
      return 0;
    }
    这样当没有数据的时候,任务会被侧地挂起,
    交出时间片
      

  16.   

    楼上的理解错了,我的外部设备中的存储器中一直是有数据的,只要用readdate去读,就能读到数据,而不是外部设备有时候会发送数据过来,有时候不会发数据过来。由于readdate执行一次要取几百个字节的数据上来,本身是要花大概1000ms左右,所以我想开线程后就一直让其不断执行,这样以最小的周期得到最新的外部设备中的数据,主线程中的定时器负责将读到的数据显示到界面上
      

  17.   

    void CDialog3::OnTimer(UINT_PTR nIDEvent)
    {
    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都试过。
      

  18.   

    不可能吧,就这样的一个OnTimer能把CPU跑满?你把里面的代码逐句注释掉,看看到底哪条语句造成CPU跑满的。
      

  19.   

    上面已经说过了,就是SetDlgItemText的问题,把SetDlgItemText全部注释就正常了,加6条左右就占了30%左右。不用SetDlgItemText显示数据,将编辑框绑定变量,通过Updata(False)的话,CPU使用也正常,但是读数据线程函数要好久才执行。我现在考虑不用定时器显示数据,但开一个线程代替定时器不知道效果怎样。
      

  20.   

    用事件机制啊,readdata在没有发出数据之后,将事件标记为已通知。
    你的读取数据的线程waitsingleobject一直等待这个事件被通知,然后再取数据。
    waitsingleobject没有返回之前,这个线程是不会不被调度到的,自然也就不占cpu。
      

  21.   

    不会吧?你做的是嵌入式?怎么CPU处理能力这么弱?如果是这样的话,那你的定时器显然不合理(其实你的CPU再强劲,这个定时器也是不合理的)。只有数据发生变化的时候你才需要更新各个Edit框,因此你显然应该是:每当子线程完成一次readdata()之后,向主线程发送自定义消息,而主线程只有在接收到自定义消息的时候才去更新Edit框,而不是用定时器更新。甚至,如果你的设备的数据很少变化的话(比如平均每隔十几秒甚至几十秒才会变化),那么你每次readdata()之后,甚至应该与上次读出的结果比较一下,如果有差别再给主线程发消息。按你的说法,“读数据的指令要花费1秒左右”,那么你弄个定时器没完没了地更新显示,纯粹是在折腾CPU。
      

  22.   

    xxd_qd说到点子上了,非常感谢,很受益。确实应该是子线程完成一次readdata()之后,向主线程发送自定义消息,而主线程只有在接收到自定义消息的时候才去更新Edit框,而不是用定时器更新,那样是在折腾CPU。至于读上来数据后,进行比较,如果有数据发生了更新才给主线程发送消息,这个建议也非常好,谢谢了。
      

  23.   

    又遇到新问题了,
    在子线程中读取数据,如果获得了数据,就发送自定义消息给主线程,消息函数中将数据显示出来,结果外部设备中数据变化后,数据显示能很快刷新,这证明子线程中不断读取数据的工作和消息响应函数中显示数据的工作都是正常的。现在在某一Edit2改写数据,在其OnEnKillfocusEdit2中写数据进设备,在设备上观测到写数据正确,并且速度很快,但是这以后,整个界面上的Edit要过1分钟左右才刷新,应该是OnEnKillfocusEdit2执行后约1分钟后子线程才开始读数据,这是什么原因?如果把显示数据的部分放到定时器中,现象和上面一样。
    如果把读数据的部分和显示数据的部分都放到定时器中,通过Edit写数据进设备后,Edit过3秒左右能刷新成写进去的值,这个速度还是比较快的,但是整个界面用Tab键移焦点,在Edit中敲数字这两项工作很慢很慢,就好像CPU的精力都用在了读数据和显示数据上来,没精力接受键盘的按键消息。难道是定时器的优先级比较高,而建立的子线程的优先级比较低,当OnEnKillfocusEdit2执行完后很久才轮到子线程执行?我试过用AfxBeginThread创建各种优先级别的子线程,但是效果还是改写数据后很久Edit中的数据才刷新。
    请教高手啊
      

  24.   

    我觉得楼主的判断条件可能都没有进去过,一直在外面进行循环判断,否则不可能出现CPU上了90%以上。
      

  25.   

    This function causes a thread to relinquish the remainder of its time slice and become unrunnable for at least the specified number of milliseconds, after which the thread is ready to run. In particular, if you specify zero milliseconds, the thread will relinquish the remainder of its time slice but remain ready. Note that a ready thread is not guaranteed to run immediately. Consequently, the thread may not run until some time after the specified interval elapses...If you have a thread that uses Sleep with infinite delay, the system will deadlock...unrunnable在Sleep非0时不完全等用于挂起并就绪等待执行,不建议使用Sleep的方式释放CPU的控制权。
    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这种标志的方法去控制是否退出线程循环,不建议这么做。
      

  26.   

    主线程是GUI线程,不应该做时间长的任务,读外部数据最好就是用工作线程,到一个缓冲区,如你全局数组,
    然后发消息到主线程,通知数据已更新,同时要做好共享数据保护,防止两个线程同时访问!少用定时器,定时器也是比较消耗资源的!同时你提到写数据时间长的问题,不知道你是如何写,通过什么机制?您觉得以现在机器配制,你这么点数据能用到这么高的CPU使用率?这么高的CPU使用率说明你有线程长时间占用了CPU!您可以试在读线程中设置一个事件,用来写数据,也可以另开一个线程专门写数据!
      

  27.   

    非常感谢大家的回复。34楼:判断条件肯定都进去了的,否则读取数据和写入数据不能都正确实现,实际是都能正确实现35楼:很抱歉我的描述问题的能力真的是太差了,需要多锻炼36楼:你的代码的意思是让我每次执行读取数据的代码后子线程停20ms?因为读数据的指令本身单独执行是要花1秒左右的,所以我认为每次执行后暂停20ms没有意义37楼:你这样说的有误,前面我已经说过了,不开子线程,把读取数据的部分和显示数据的部分放到定时器中,写数据的部分放到每个Edit的OnEnKillfocusEdit中,是能够实现正确的数据读和写的,只不过这时程序对键盘的输入反映很迟钝,CPU使用在4%和30%之间跳跃。如果这里能解决程序对键盘的操作反映迟钝的现象,我的整个问题也解决了,即使CPU不知什么原因使用很高,但程序还是可以正常使用的。38楼:我不可能不用定时器,显示到Edit里的数据需要定时刷新,即使这个可以用31楼的方法代替定时器,还有一些动画是根据设备中数据的变化而动作的,所以不可能不用定时器。你说的数据保护,我请教下我这里是子线程读取数据,然后写进全局数组中,显示数据的部分从全局数组中取出数据,不涉及到两个线程同时写全局数组,有必要做数据保护吗?
    现在我发现大家对我的情况理解有误,我想再次描述下
    非模态对话框上有一些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)一样。
      

  28.   

    道理很简单:没有子线程的时候,你的程序是单线程的,你在敲键盘的时候,实际上是在向你的消息队列发送WM_KEYDOWN和WM_KEYUP。这两个消息被夹杂在大量的WM_TIMER序列中间,而你每处理一个WM_TIMER就会执行一遍readdata,而readdata是需要1秒的,所以你的键盘响应不慢才怪。从这里也可以看出,不额外开线程是不行的。既然开了线程,那么就存在与主线程如何进行并发控制的问题。从你所实现的功能来看,起码有两项是需要进行并发控制的:
    1、数据缓冲区。子线程要往里放从设备中读出的数据,主线程要用它来刷新显示。不过这个问题好解决:只要子线程用SendMessage而不是PostMessage给主线程发消息即可,无须采取其它措施。顺便说一句,你子线程中的Sleep应该删掉。既然你的设备读取需要1秒钟,那么再用Sleep来给CPU减压毫无必要。
    2、设备总线。你的子线程在不断地读设备,而你在往设备里写数据的时候,是用主线程写的吧?你的设备是什么、是否支持同时读写我不清楚,但既然你说单线程时没有停一分钟的问题,那么最大的可能就是:你的设备总线在遇到写指令的时候,会把当前正在执行的读指令阻塞、或者中断(readdata既然要一分钟,那么你每次写的时候都几乎必然会遇到一个readdata正在执行当中)。而你的readdata在迟迟没有接到数据的情况下会以失败告终,那个1分钟其实就是Timeout。当然,你的设备并没有停止响应,当它写完以后,你用别的方法(另一个程序或者线程)再去读它,它仍然能很好地读出来,只不过在写指令之前的那个读指令被它Cancel了而已。
      

  29.   

    太谢谢xxd_qd,水平又高,人又好,佩服不额外开线程是不行的解释很好。关于设备总线,我往设备写数据是在主线程的Edit的OnEnKillfocusEdit事件函数中做的。设备是否支持同时读写?是支持的,我之前在单线程的定时器理读数据,写数据的时候做一个关开定时器和不做效果没有两样,都能实现数据的正确刷新,只不过键盘响应很慢。你后面说的可能写指令会阻塞读指令,如果是这样,怎么解释用单线程中,定时器中读数据,写数据后显示的数据能马上刷新而不是需要1分钟?现在的问题剩下为什么写数据后,显示的数据要1分钟才刷新,正常情况下需要1-2秒才对。这里我要说的是,写一个数据下去只需0.1秒左右,读一个数据上来也只需0.1秒左右,一个界面的所有数据一起读上来需要1秒左右。我在一个按钮下做
    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分钟呢?
      

  30.   

    你可能没太理解我说的意思。
    当你在界面(主线程)的编辑框中更改数据的时候,你的子线程是在不停地循环读取数据吧?当你界面上某个编辑框失去焦点的时候,你的主线程会向设备写入数据,这没错吧?由于你的子线程是不停地循环读数据的,因此,不论你读一个数据需要1秒、0.1秒、甚至0.0001秒,当你主线程对设备发出“写入数据”的指令的那个瞬间,你的子线程都一定是在读某个数据的过程中(因为你的子线程除了读数据之外不干别的了,如果那个瞬间不是在读数据的话,那你说它在干什么?)。好,假定你的子线程在第10秒的时候发出了一个读指令,根据你的说法,本来在第10.1秒的时候数据就返回来了,但问题是:你的主线程在第10.05秒的时候发出了一个写指令,而你的设备的响应方式是:假若在前一指令没执行完的时候又接到一条新指令,则放弃前一条指令。于是,当在第10.05秒设备接到你的写指令的时候,设备会放弃还没有完成的那条读指令,转而执行这条新的写指令。于是,你的主线程会在第10.15秒的时候写入成功而返回,并且设备也处于空闲状态了。但你的子线程却不知道这一切,它知道的仅仅是:设备一直没有把数据返回来,于是它就等啊等啊,直到等得实在不耐烦了(你的那些readdata、writedata之类的函数,内部肯定会有timeout方面的设置,如果过多长时间设备没有响应的话,就算操作失败),它才会以失败告终,而这个让它“等得不耐烦”的时间,恐怕就是1分钟。于是1分钟之后,本次读取操作失败,readdata函数返回,你的子线程继续运行,继续对设备发出读指令,并顺利读出,一切都又正常了。
      

  31.   

    明白你的意思了,非常感谢。
    那么,如果在写数据完成后,想办法让子线程中的ReadData重新开始执行,而不是做等待返回值的工作,就不会出现写数据后1分钟显示数据才刷新的问题了。那么这个怎么做呢,我试过在写数据的时候用
    SuspendThread(hThreadl1);
    ResumeThread(hThreadl1);
    无论是WriteData之前调用还是之后调用SuspendThread(hThreadl1),情况都没有改变,现在发现应该是线程挂起时线程函数在等待读数据的返回,结束挂起时还是在等待读数据的返回。有什么办法在OnEnKillfocusEdit中写数据后让线程函数从头开始执行而不是从挂起时的位置开始执行呢?
      

  32.   

    你既然做多线程,那么最起码的基础是学会如何做线程间同步。尤其是你的两个线程之间还有两种共享资源(数据buffer和设备),同步起来还要注意死锁,比较复杂一点。建议你还是专门去找一些线程同步方面的教材资料之类的东西学习一下,否则你的程序以后还可能出现各种各样的毛病。多线程不是那么容易做的。
      

  33.   

    问题解决了,又开了个子线程用来写数据,读线程和子线程同步就解决了问题,用的是临界区,之前,写数据放在主线程中,试过多次,不果。感谢大家,感谢xxd_qd