主界面建立线程,用TIdTCPClient读取 服务器端发来的数据
procedure TForm3.Button1Click(Sender: TObject);
begin
   recvthread := TRev1.Create(True);
   recvthread.FreeOnTerminate := True;
   recvthread.Resume;
end;线程单元中:procedure TRev1.Execute;
begin
  { Place thread code here }
     while not Terminated do
   begin
      Form3.Memo1.Lines.Add(Form3.IdTCPClient1.ReadLn('EOF', -1 , -1));  //关闭时被卡这里,无法正常关闭线程!!你说咋办??????
   end;
end;问题是,我在界面关闭线程时,
procedure TForm3.Button3Click(Sender: TObject);
begin
     recvthread.Terminate;////////////////////线程无法关闭,,, 直接关闭窗口将引发异常!!!   我用delphi5
end;
请问各位同志,有什么解决方法吗??

解决方案 »

  1.   

    begin
          Form3.Memo1.Lines.Add(Form3.IdTCPClient1.ReadLn('EOF', -1 , -1));  //关闭时被卡这里,无法这句有点问题,在后面加这个看看如何:
    sleep(500);
     recvthread.Terminate;
    修改为:
      recvthread.Terminated := true;同样,要和上面的修改配合
      

  2.   

    Execute里不能直接用VCL控件,否则会锁死界面,Terminate的问题也是因为这个引发的。如果收到数据,用postmessage发消息到主窗体,也可以用Synchronize();来处理界面更新。
      

  3.   

    在主界面单元中,修改如下:
    procedure TForm3.Button1Click(Sender: TObject);
    begin
       recvthread := TRev1.Create(memo1,IdTCPClient1);//传入参数,在线程中更新memo
    end;在线程单元中,如下:unit Unit4;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
      ComCtrls;
    type
      TRev1 = class(TThread)
      private
        { Private declarations }
      protected
        procedure Execute; override;
        procedure Write_memo;
      public
        constructor Create(memo:Tmemo;IdTCPClient:TIdTCPClient);
      end;implementation
    uses unit3;
    { Important: Methods and properties of objects in VCL can only be used in a
      method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TRev.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TRev }
    constructor TRev1.Create(memo:Tmemo;IdTCPClient:TIdTCPClient);
    begin
       memo.Lines.Clear;
       FreeonTerminate:=true;
       inherited Create(false);
    end;
    procedure TRev1.Execute;
    begin
      { Place thread code here }
         while not Terminated do
       begin
        //  Form3.Memo1.Lines.Add(Form3.IdTCPClient1.ReadLn('EOF', -1 , -1));
         synchronize(Write_memo);
       end;
    end;procedure TRev1.Write_memo;
    begin
       memo.lines.add(IdTCPClient.ReadLn('EOF', -1 , -1));
    end;end.还是编译不成功!!提示procedure TRev1.Write_memo  中用到的参数memo没定义 ,,这个memo就是来自界面单元的。。
      

  4.   

    你IDTCPCLIENT接收数据的时候,又没有设置超时,它又是阻塞模式,当然会阻塞在那儿.
    线程当然得不到结束.
    1,为什么不在主线程用INDYTCPCLIENT?INDY控件组设计的一个特点就是为主线程运行阻塞方式客户端防界面冻结作了一定处理.2,接收数据为什么不设置超时?
    3,用线程,尽可能不要直接去访问FORM这些GDI显示的.尽管有Synchronize可以来保证线程
    安全,但它实际是用消息机制切换任务到主线程执行,失去了线程的意义.
      

  5.   

    多谢哈欠先生,以及各位同志的教诲,小弟新手,再问一下,有啥办法可以使INDYTCPCLIENT不断读书,又可使超时时候退出读数??
      

  6.   

    INDY10,idTCPConnection 都有 IOHandler 属性,
    通过      // 一定时间检查是否有数据可读
    IOHandler.CheckForDataOnSource(GetTimeout); 
          Result := IOHandler.InputBuffer.Size;
          if Result > 0 then // 有数据到达再用相应的
    IOHandler.ReadXXXX 读出数据。循环该过程,并且判断线程是否结束。严重支持楼上仁兄建议的,在线程里 PostMessage 给主线程,
    让主线程操作VCL
      

  7.   

    回复lunyx (天伦我独享) 
    "还是编译不成功!!提示procedure TRev1.Write_memo  中用到的参数memo没定义 ,,这个memo就是来自界面单元的。。"在线程中定义一个TMemo类型的变量memo1,在constructor TRev1.Create(memo:Tmemo;IdTCPClient:TIdTCPClient);中初始化memo1,并把memo赋值给memo1
    例如:
    constructor TRev1.Create(var memo:Tmemo;IdTCPClient:TIdTCPClient);
    begin
      memo1:=Tmemo.Create(nil);
      memo1 := memo;
    end;
      

  8.   

    该怎么postMessage?能不能做个示范小动作?
      

  9.   

    该怎么postMessage?能不能做个示范小动作?
      

  10.   

    客户端开线程接收操作不好,容易丢数据.你是用长连接吗?其实最简单的方法就是添加几个阻断器,比如IdLogEvent1.连接建立后,用他来接收数据.你上面的代码,我修改了一下,你试试
    procedure TForm3.Button1Click(Sender: TObject);
    begin
       recvthread := TRev1.Create(memo1,IdTCPClient1);//传入参数,在线程中更新memo
    end;在线程单元中,如下:unit Unit4;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
      ComCtrls;
    type
      TRev1 = class(TThread)
      private
         Mymemo:Tmemo;
         IdTCPClient1:TIdTCPClient;
        { Private declarations }
      protected
        procedure Execute; override;
        procedure Write_memo;
      public
        constructor Create(memo:Tmemo;IdTCPClient:TIdTCPClient);
      end;implementation
    uses unit3;
    { Important: Methods and properties of objects in VCL can only be used in a
      method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TRev.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TRev }
    constructor TRev1.Create(memo:Tmemo;IdTCPClient:TIdTCPClient);
    begin
       inherited Create(false);
       //memo.Lines.Clear;
       Mymemo := memo;
       IdTCPClient1:= IdTCPClient;
       FreeonTerminate:=true;
    end;
    procedure TRev1.Execute;
    begin
      Mymemo.Lines.Clear;
      { Place thread code here }
         while not Terminated do
       begin
        //  Form3.Memo1.Lines.Add(Form3.IdTCPClient1.ReadLn('EOF', -1 , -1));
         synchronize(Write_memo);
       end;
    end;procedure TRev1.Write_memo;
    begin
       Mymemo.lines.add(IdTCPClient1.ReadLn('EOF', -1 , -1));
    end;end.
      

  11.   

    完整单元,在界面上放一个 memo 一个 button, 一个 idTcpClient.
    我用的 indy 是10.1.5:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
      StdCtrls;
    const
      WM_GETINFO = WM_USER + 110;
    type
      TReceiver = class(TThread)  protected
        procedure Execute; override;
      public
        Connection: TidTCPConnection;
        MsgHandle: THandle;
      end;  TForm1 = class(TForm)
        Memo1: TMemo;
        Button1: TButton;
        IdTCPClient1: TIdTCPClient;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        /// 界面上需要处理线程Post 出来的 Message
        procedure WMGetInfo(var msg: TMessage); message WM_GETINFO;
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TReceiver.Create(true) do
      begin
        FreeOnTerminate := true;
        Connection := self.IdTCPClient1;
        MsgHandle := Handle;
        resume;
      end;
    end;procedure TForm1.WMGetInfo(var msg: TMessage);
    var
      buf: PChar;
      iLen: integer;
      strTmp: string;
    begin  iLen := msg.WParam;
      buf := PChar(msg.LParam);
      SetLength(strTmp, iLen);
      Move(buf^, strTmp[1], iLen);
      //// 线程抛出的信息被放到  strtmp 中,
      //// 下面可以加入你自己的处理
      Memo1.Lines.Add(strTmp);
      /// 记得 Free,不然存在内存泄漏。
      Freemem(buf);
    end;
    { TReceiver }procedure TReceiver.Execute;
    var
      buf: PChar;
      iLen: integer;
      strTmp: string;
      iRec: integer;
    begin
      while not Terminated do
      begin
        /// 10 ms 检查一次是否有数据到达
        Connection.IOHandler.CheckForDataOnSource(10);
        iRec := Connection.IOHandler.InputBuffer.Size;
        if iRec > 0 then
        begin
          /// 你的接收数据处理过程
          strTmp := Connection.IOHandler.ReadString(iRec);      GetMem(buf, iRec);
          Move(strTmp[1], buf^, iRec);
          /// 需要向主界面输出信息时,向主界面的窗口句柄
          /// Postmessage , SendMessage 也行。
          PostMessage(MsgHandle, WM_GETINFO, iRec, integer(buf));
        end;
      end;
    end;end.
      

  12.   

    创建线时,要改一下: MsgHandle := self.Handle;
      

  13.   

    恒星的方法不行啊,还是出现老问题,darnis(文子)的方法编译通不过啊,
     Connection.IOHandler.CheckForDataOnSource(10);//CheckForDataOnSource(10);找不到该方法
     iRec := Connection.IOHandler.InputBuffer.Size;//InputBuffer.Size也找不着该属性
      

  14.   

    找不到我写的方法是因为你的INDY版本跟我的不一样,
    我用的是10.1.5
    我已经说过很多次了。