我正在使用一个线程来访问pop3帐户并检索邮件。它工作得很好,但它会锁定我的应用程序,直到它完成。不能移动窗口,关机,点击按钮,什么都不做。
它运行得很好,允许我访问主应用程序,直到我注释掉的地方(或者在IdPOP31.Connect();之后)
//获取服务器拥有的消息数
然后它就锁住了
procedure TPopThread.Pop;
var
vName, vEmail, vServerIn, vServerOut, vUserId, vPassword: String;
vPop3Port, vSMTPPort, vSSL: String; vHTML: TStringList;
MsgCount : Integer;
i,j : Integer;
FMailMessage : TIdMessage;
begin
with frmMain do
begin
RzMemo1.Lines.Clear;
vHTML:= TStringList.Create;
GetAccount(lbxMain.SelectedItem,vName, vEmail, vServerIn, vServerOut, vUserId, vPassword,
vPop3Port, vSMTPPort, vSSL, vHTML);
IdPOP31.Host := vServerIn;
IdPOP31.Username := vUserId;
IdPOP31.Password := vPassword;
IdPOP31.Port := StrToInt(vPop3Port);
try
Prepare(IdPOP31);
IdPOP31.Connect();
// {
// //Getting the number of the messages that server has.
// MsgCount := IdPOP31.CheckMessages;
// for i:= 0 to Pred(MsgCount) do
// begin
// try
// FMailMessage := TIdMessage.Create(nil);
// IdPOP31.Retrieve(i,FMailMessage);
// RzMemo1.Lines.Add('=================================================');
// RzMemo1.Lines.Add(FMailMessage.From.Address);
// RzMemo1.Lines.Add(FMailMessage.Recipients.EMailAddresses);
// RzMemo1.Lines.Add(FMailMessage.Subject);
// RzMemo1.Lines.Add(FMailMessage.Sender.Address);
// RzMemo1.Lines.Add(FMailMessage.Body.Text);
//
// for J := 0 to Pred( FMailMessage.MessageParts.Count ) do
// begin
// // if the part is an attachment
// if ( FMailMessage.MessageParts.Items[ J ] is TIdAttachment) then
// begin
// RzMemo1.Lines.Add('Attachment: ' + TIdAttachment(FMailMessage.MessageParts.Items[J]).Filename);
// end;
// end;
// RzMemo1.Lines.Add('=================================================');
// finally
// FMailMessage.Free;
// end;
// RzMemo1.Clear;
// end;
// }
finally
IdPOP31.Disconnect;
vHTML.Free;
end;
end;
end;它实际上是在我添加线程之前完成的,所以它与被注释掉的部分有关,而不是线程
我做错了什么或没做什么?
下面是我的执行
procedure TPopThread.Execute;
begin
try
Synchronize(Pop);
except
on Ex: Exception do
fExceptionMessage := Ex.Message;
end;
end;我是这样称呼它的
PopThread := TPopThread.Create(lbxMain.SelectedItem, frmMain.DonePopping);发布于 2013-02-28 23:51:33
您将自己锁定应用程序,因为您正在synchronizing对pop方法的调用。
Synchronize使AMethod指定的调用使用主线程进行执行,从而避免多线程冲突。
当前线程在AThread参数中传递。
如果不确定方法调用是否是线程安全的,请从Synchronize方法中调用它,以确保它在主线程中执行。当方法在主线程中执行时,当前线程的执行被挂起。
因此,出于实际目的,您就好像没有额外的线程,因为所有代码都是在主线程中执行的。
例如,当您想要与VCL组件进行交互时,就需要使用Synchronize
另一方面,因为您直接从方法访问许多可视化控件,而VCL不是线程安全的,所以您必须在主线程中执行您的方法。
最好的做法是使线程独立于VCL,方法是不从线程访问任何VCL组件,而是收集内存中的所有输入和输出值,并在线程开始之前和线程结束后从主线程中设置/读取这些值。
或者,如果出于任何原因您不想这样做,您可以剖析您的方法,以分离需要访问VCL的部分,并仅同步这些部分,例如:
type
TPopThread = class
private
FMailMessage : TIdMessage; //now the message belongs to the class itself
...
public
//all the values are passed via constructor or the thread is
//created in suspended state, configured and then started
property Host: string read FHost write FHost;
property UserName: string read FUserName write FUserName;
property Password: string read ...;
property Port: Integer read ...;
end;
procedure TPopThread.CopyMailToGUI;
var
J: Integer;
begin
frmMain.RzMemo1.Lines.Add('=================================================');
frmMain.RzMemo1.Lines.Add(FMailMessage.From.Address);
frmMain.RzMemo1.Lines.Add(FMailMessage.Recipients.EMailAddresses);
frmMain.RzMemo1.Lines.Add(FMailMessage.Subject);
frmMain.RzMemo1.Lines.Add(FMailMessage.Sender.Address);
frmMain.RzMemo1.Lines.Add(FMailMessage.Body.Text);
for J := 0 to Pred( FMailMessage.MessageParts.Count ) do
begin
// if the part is an attachment
if ( FMailMessage.MessageParts.Items[ J ] is TIdAttachment) then
begin
frmMain.RzMemo1.Lines.Add('Attachment: ' + TIdAttachment(FMailMessage.MessageParts.Items[J]).Filename);
end;
end;
frmMain.RzMemo1.Lines.Add('=================================================');
end;
procedure TPopThread.Pop;
var
MsgCount : Integer;
i,j : Integer;
Pop: TIdPOP3;
begin
Pop := TIdPOP3.Create(nil);
try
Pop.Host := FHost;
Pop.Username := FUserName;
Pop.Password := FPassword;
Pop.Port := FPort;
Prepare(Pop);
Pop.Connect();
//Getting the number of the messages that server has.
MsgCount := Pop.CheckMessages;
for I := 0 to Pred(MsgCount) do
begin
try
FMailMessage := TIdMessage.Create(nil);
try
IdPOP31.Retrieve(i,FMailMessage);
Synchronize(CopyMailToGUI);
finally
FMailMessage.Free;
end;
end;
finally
Pop.Free;
end;
end;
procedure TPopThread.Execute;
begin
//no need of a try/except, if an exception occurs, it
//is stored in the FatalException property
Pop;
end;现在,您的线程将请求主线程仅将处理后的消息复制到VCL。在复制期间,您的线程将阻塞,您的应用程序将不会响应消息,因为主线程很忙,但这将是非常短的时间间隔,所以即使这不是理想的情况,我认为它将为您想要的工作。
发布于 2013-02-28 23:50:07
您可以将所有逻辑都放在Synchronize调用中。Synchronize在主VCL线程中运行它的函数,因此您实际上已经从一开始就取消了使用单独线程可能获得的任何好处。
删除对Synchronize的调用,以便Pop在您为其创建的线程中运行。
如果您仍然需要在主线程中执行一些操作,那么可以将它们放在子例程中,以便只能在Synchronize中运行它们。我在这段代码中看到的部分是向memo控件添加行的地方。
https://stackoverflow.com/questions/15138529
复制相似问题