我有一个 Windows 服务项目,它启动一个线程来做一些工作,这部分已经工作了很长时间,所以不是问题的一部分。我想要做的是当这个工作开始和结束时,它应该启动另一个线程(继承 TThread 的 EventMessenger)来发送电子邮件,通知工作已经开始和结束。我知道你不能有嵌套线程,但我认为从另一个线程启动一个线程应该没问题,那么它将只属于主进程。我在挂起模式下创建线程,但我不确定是否可以在挂起时为线程对象上的对象调用分配。
EventMessenger := TEventMessenger.Create(true); // true = start suspended
EventMessenger.StatusCode := AStatusCode;
EventMessenger.Receiver.Assign(Receiver);
EventMessenger.MessageOptions.Assign(MessageOptions);
EventMessenger.MessageDetails := AMessage;
EventMessenger.FreeOnTerminate := true;
EventMessenger.Resume;
TEventMessenger 的 Execute 使用 Indy TIdSmtp 发送邮件,这里是部分代码
try
self.FMessage.From.Address := ASender;
self.FMessage.Recipients.EMailAddresses := AReceiver;
self.FMessage.Subject := ASubject;
self.FMessage.Body.Text := AMessage;
try
self.FSMTP.Connect;
self.FSMTP.Send(self.FMessage);
except
on E:EIdException do
begin
CurrentEurekaLogOptions.ExceptionDialogOptions := []; // Don't show dialog box
StandardEurekaNotify(E, ExceptAddr()); // Save exception to file
end;
end;
finally
if self.FSMTP.Connected then
self.FSMTP.Disconnect;
end;
我第一次启动线程 EventMessenger 时它工作正常,并发送一封关于工作已经开始的电子邮件。但是,当它再次启动 EventMessenger 以发送有关作业已停止的邮件时,我在 ntdll 中遇到了堆栈溢出。我想知道挂起模式下的assign是否会弄乱堆栈或者indy是否有问题;读到如果在混合托管/非托管代码时未屏蔽异常,则可能会出现问题,不确定这是否与此有关。注意:我没有使用 Delphi 2009 中的默认 Indy,因为它有几个错误,我正在使用 1 月份从他们的存储库下载的 Indy10 代码运行。
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
:779e010f ntdll.KiUserExceptionDispatcher + 0xf
:77a2878b ; ntdll.dll
任何人都知道导致堆栈溢出的实际问题是什么,或者我如何捕获异常?我已经将 indy 发送包装在 try/except 中,但我猜它只适用于主进程而不是线程,所以我还在 EventMesssenger.Execute 中的代码周围添加了一个 try/except,它调用了我已经实现的 HandleException,如下面的代码,但是它在没有进入 ExceptionHandler 的情况下使用 AV 服务崩溃。
procedure TEventMessenger.DoHandleException;
begin
if FException is Exception then
begin
CurrentEurekaLogOptions.ExceptionDialogOptions := []; // Don't show dialog box
StandardEurekaNotify(FException, ExceptAddr()); // Save exception to file
end;
end;
procedure TEventMessenger.HandleException;
begin
FException := Exception(ExceptObject);
try
if not (FException is EAbort) then
Synchronize(DoHandleException);
finally
FException := nil;
end;
end;