最近刚接触Delphi多线程,写代码时遇到了一个问题,请教高手!
我想实现的是,一个主线程负责GUI部分,两个子线程负责数据处理部分,子线程处理完毕后,发送同一个消息给主线程,消息通过WParam和LParam来区分,主线程开始在Tchart控件上绘制,完毕后等待下一次的消息,这个消息是在一个死循环中不断发送的,所以TChart控件会不断重绘,直到有结束标志,才会停止。两个子线程分别在两个TChart控件上绘图,处理结果分别在两个TChart控件上以波形显示出来。
出现的问题是,开始时两个线程都跑了,并且两个TChart都能显示并且重绘,可是过一会,大概20秒后,显示第一个线程数据的TChart控件停止重绘了,第二个TChart控件还能继续重绘,实在不知道为什么???
下面是代码的精简部分:
{*全局变量和函数声明*}
function ManageData(card_number:smallint;gnADChn:Word;gnCount:Integer;gain:Smallint;gnbuffer:array of word):boolean;  //数据处理函数,供两个子线程调用
gnbufferX,gnbufferX1: array of Word ; //两个子线程存放处理后数据的存储区
Const WM_MYMESSAGE = WM_USER+1000;{*子线程的执行部分*}
procedure MyThread.Execute;
begin
    Repeat
      ManageData(card_number,gnADChn,gnCount,gain,gnbuffer);  //调用ManageData来处理数据.
      application.ProcessMessages; 
    Until stop_flag;
end;{*数据处理函数定义*}
function ManageData(card_number:smallint;gnADChn:Word;gnCount:Integer;gain:Smallint;gnbuffer:array of word):boolean;
begin
  SetLength(gnbufferX,1024);  //开辟存储区大小.
  SetLength(gnbufferX1,1024);
  if card_number = 1 then
  begin
      For i:=0 to 1023 do  
      begin
        gnbufferX[i] := gnbuffer[i*(gnADChn+1)*2+k*2];
      end;
      PostMessage(Form1.Handle, WM_MYMESSAGE,0,card_number); //如果线程1处理完毕,发送消息到主线程
  end;
  if card_number = 0 then
  begin
      For i:=0 to 1023 do
      begin
        gnbufferX1[i] := gnbuffer[i*(gnADChn+1)*2+(k-16)*2];
      end;
      PostMessage(Form1.Handle, WM_MYMESSAGE,1,card_number); //如果线程2处理完毕,发送消息到主线程
  end;
  result := true;
end;{*主线程中消息响应部分*}
procedure TForm1.OnWM_MYMESSAGE(var MSG:TMessage);
begin
    if MSG.LParam = 1 then  //通过LParam来区分显示哪块存储区
    begin
      Form1.Showdata(MSG.WParam,15,512*8,1,gnbufferX);
    end;
    if MSG.LParam = 0 then
    begin
      Form1.Showdata(MSG.WParam,15,512*8,1,gnbufferX1);
    end;
end;{*主线程中显示部分,涉及到TChart控件*}
procedure Tform1.ShowData(x:Integer;gnADChn:Word;gnCount:Integer;gain:Smallint;gnbuffer:array of word);
var
  i:Integer;
  chart :array of Tchart;
  Showgnbuffer: array of Integer;
Begin
  setlength(chart,2) ;
  chart[0]:=chart1;
  chart[1]:=chart2;  SetLength(Showgnbuffer,1023); 
  Chart[x].Series[0].Clear;
  For i:=0 to 1023 do
  begin
    if gnbuffer[i]>32767 then
     begin
       Showgnbuffer[i]:=(gnbuffer[i]-65536) //数组由word型变成intger型
     end
    else
     begin
       Showgnbuffer[i]:=gnbuffer[i];
     end;
    Chart[x].Series[0].AddXY(i,(Showgnbuffer[i])*10/(32768*gain),'',clblue);
  end;
end;

解决方案 »

  1.   

    好长呀  好复杂如果消息要立即处理 建议 PostMessage(Form1.Handle, WM_MYMESSAGE,1,card_number); //如果线程2处理完毕,发送消息到主线程 
    //改为
     Sendermessage(Form1.Handle, WM_MYMESSAGE,1,card_number); //如果线程2处理完毕,发送消息到主线程 
      

  2.   

    application.ProcessMessages; 是什么意思呢?这里需要吗?很多地方都看得不明白.编程风格挺特别的,呵呵。如果是我会定义两个线程类,然后把managedata放到线程里定义。你是产生两个mythread的实例分别为1和2吗?那么怎么区分的card_number呢?
      

  3.   

    PostMessage是把事件发送到队列,主线程处理的时候可能和线程同时访问gnbuffer,不知道是不是这样带来的死锁。
      

  4.   

    代码比较乱,给几点说明:
    1、MyThread的实例作为TForm1的成员变量
    2、不要使用Form1这个全局变量,线程中可要使用它的Handle,你可以在Form中创建MyThread的实例时把Handle传递进去作为MyThread的成员变量保存
    3、OnWM_MYMESSAGE不要写Form1.Showdata,直接写Showdata就可以了
    4、线程的Execute不要调用application.ProcessMessages
    5、ManageData改成MyThread的成员方法比较好
    6、gnbufferX变成MyThread的成员变量,SetLength(gnbufferX,1024)在MyThread创建时就设置好
    7、ShowData中需要使用gnbuffer,因此你可以在MyThread中将gnbufferX当成属性发布
    8、其实MyThread中有保护方法Synchronize,可以直接同步到主线程调用,因此你可以不用发消息,而将ShowData作为MyThread的成员方法,用Synchronize进行调用就可以了