我正在使用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;
所以函数是这样的:
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;
所以,如果不想,你不需要阅读。但我正在连接到一些远程主机,并接收它的文本,如果收到的文本以“+”符号开头(默认为POP3服务器),我返回true ...但是当我尝试在Thread.Execute中执行此操作时:
if CheckPOPHost = true then
begin
Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
只是不工作。我认为很好记住,如果在函数内部,而不是做:
if AnsiStartsStr('+', ReceivedText) then
Result:= true;
我做:
if AnsiStartsStr('+', ReceivedText) then
Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
它正常工作......发生了什么事?!
编辑::我在'如果CheckPOPHost = true然后'行时收到错误。由于某些未知原因,它会出现访问冲突错误。
答案 0 :(得分:6)
您正在从线程调用非线程安全的VCL方法。
Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
永远不要那样做。
将来电换入Synchronize( YourThread.SendString)
;线程中的方法。
示例:
MyThread.SendString;
begin
Form1.Memo1.Lines.Append('Valid HOST:: '+Host);
end;
在你的线程的某个地方执行:
if CheckPOPHost = true then
begin
Synchronize(SendString);
更新2:
根据您对CheckPOPHost
中释放对象的评论:围绕这些对象封闭try..finally
块,并在CheckPopHost中附加try..except
块。
<强>更新强>
出现了关于评论中的线程向导的讨论。 如果您在向导界面后创建一个线程单元,那么这就是您所获得的:
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.
答案 1 :(得分:5)
您正在致电
SockStream.Free
即使您没有输入创建SockStream的块。这意味着您的代码可以在未初始化的变量上调用Free。这是我可以看到访问冲突的唯一原因。你需要在if块中移动Free。
另外,在创建对象时始终使用try / finally:
SockStream := TWinSocketStream.Create (MySocket.Socket, 1000);
try
....
finally
SockStream.Free;
end;
如果你这样编写,编译器就不会让你把Free放在错误的块中。
你应该对MySocket做同样的事。
并且不要从线程中访问GUI,但我认为其他人已经明确指出了这一点!