1

我有一个 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;
4

2 回答 2

1

回答您的问题 -Assign()在线程暂停时可以正常工作。您没有像Assign()的方法那样接触堆栈,TPersistent并且 Delphi 对象存在于堆上,而不是堆栈上。

堆栈溢出通常意味着您遇到了一个永不结束的递归函数调用。在调试器中运行代码并在发生溢出时查看调用堆栈,这将帮助您诊断哪个函数卡在递归循环中。

于 2013-08-08T17:56:50.290 回答
0

在这里找到了我的答案,似乎它与微软忘记删除的硬编码断点有关。 Rad Studio 调试器线程中未处理的异常

于 2013-08-19T12:05:48.883 回答