在线程内访问函数结果

HwT*_*rap 0 delphi delphi-2010

我正在使用Threads(再次),这总是很痛苦......我的线程类中有一个函数,它是私有的.该函数返回一个布尔结果,以检查某个POP3服务器是否有效.检查工作,我测试了,看起来像至少工作,但我在Thread.Execute程序中尝试访问结果时遇到问题.我将解释更多,让我们去代码..这是宣言:

type
  MyThread = class(TThread)
  public
    constructor Create(HostLine: string);
  protected
    procedure Execute; override;
    procedure MainControl(Sender: TObject);
  private
    Host: string;
    function CheckPOPHost: boolean; //this is the problematic function
  end;
Run Code Online (Sandbox Code Playgroud)

所以函数是这样的:

function MyThread.CheckPOPHost: boolean;
var
  MySocket: TClientSocket;
  SockStream: TWinSocketStream;
  Buffer: array[0..1023] of Char;
  ReceivedText: string;
begin
  Result:= false;
  FillChar(Buffer, SizeOf(Buffer), #0);
  MySocket:= TClientSocket.Create(Nil);
  MySocket.Port:= 110;
  MySocket.ClientType:= ctBlocking;
  MySocket.Host:= Host;
  MySocket.Active:= true;
  if (MySocket.Socket.Connected = true) then
    begin
      SockStream := TWinSocketStream.Create(MySocket.Socket, 1000);
      SockStream.WaitForData(10000);
      while (SockStream.Read(Buffer, SizeOf(Buffer)) <> 0) do
        ReceivedText:= ReceivedText + Buffer;
      if Length(ReceivedText) > 0 then
        ReceivedText:= PAnsiChar(ReceivedText);
      if AnsiStartsStr('+', ReceivedText) then
        Result:= true;
    end;
  SockStream.Free;
  MySocket.Free;
end;
Run Code Online (Sandbox Code Playgroud)

所以,如果不想,你不需要阅读.但我正在连接到一些远程主机,并接收它的文本,如果收到的文本以"+"符号开头(默认为POP3服务器),我返回true ...但是当我尝试在Thread.Execute中执行此操作时:

 if CheckPOPHost = true then
    begin
      Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
Run Code Online (Sandbox Code Playgroud)

只是不工作.我认为很好记住,如果在函数内部,而不是做:

  if AnsiStartsStr('+', ReceivedText) then
    Result:= true;
Run Code Online (Sandbox Code Playgroud)

我做:

  if AnsiStartsStr('+', ReceivedText) then
    Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
Run Code Online (Sandbox Code Playgroud)

它正常工作......发生了什么事?!

编辑::我在'如果CheckPOPHost = true然后'行中收到错误.由于某些未知原因,它会给出访问冲突错误.

LU *_* RD 6

您正在从线程调用非线程安全的VCL方法.

Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
Run Code Online (Sandbox Code Playgroud)

永远不要那样做.

将呼叫包裹在一个Synchronize( YourThread.SendString); 线程中的方法.

例:

MyThread.SendString;
begin
  Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
end;
Run Code Online (Sandbox Code Playgroud)

在你的线程中的某个地方执行:

if CheckPOPHost = true then
  begin
    Synchronize(SendString);
Run Code Online (Sandbox Code Playgroud)

更新2:

从您关于释放对象的注释中CheckPOPHost:try..finally围绕这些对象封闭块以及try..exceptCheckPopHost中的其他块.

更新

出现了关于评论中的线程向导的讨论.如果您在向导界面后创建一个线程单元,那么这就是您所获得的:

unit Unit21;

interface

uses
  System.Classes;

type
  TMYTHREADTEST = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

{
  Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure TMYTHREADTEST.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end;

    or

    Synchronize( 
      procedure
      begin
        Form1.Caption := 'Updated in thread via an anonymous method' 
      end
      )
    );

  where an anonymous method is passed.

  Similarly, the developer can call the Queue method with similar parameters as 
  above, instead passing another TThread class as the first parameter, putting
  the calling thread in a queue with the other thread.

}

{ TMYTHREADTEST }

procedure TMYTHREADTEST.Execute;
begin
  { Place thread code here }
end;

end.
Run Code Online (Sandbox Code Playgroud)


Dav*_*nan 5

你在打电话

SockStream.Free
Run Code Online (Sandbox Code Playgroud)

即使您没有输入创建SockStream的块.这意味着您的代码可以在未初始化的变量上调用Free.这是我可以看到访问冲突的唯一原因.你需要在if块中移动Free.

另外,在创建对象时始终使用try/finally:

SockStream := TWinSocketStream.Create (MySocket.Socket, 1000);
try
  ....
finally
  SockStream.Free;
end;
Run Code Online (Sandbox Code Playgroud)

如果你这样编写它,编译器就不会让你把Free放在错误的块中.

你应该对MySocket做同样的事情.

并且不要从线程访问GUI,但我认为其他人已经明确地说明了这一点!