私は何らかの仕事をするためにスレッドを開始するWindowsサービスのプロジェクトを持っています.この部分は長い間働いていたので、問題の一部ではありません. 私がやろうとしているのは、このジョブが開始および終了したときに、別のスレッド (TThread を継承した EventMessenger) を開始して、ジョブの開始と終了に関する通知を電子メールで送信することです。スレッドをネストできないことはわかっていますが、あるスレッドを別のスレッドから開始しても問題ないと思います。そうすれば、それはメインプロセスに属します。サスペンド モードでスレッドを作成しましたが、サスペンド中にスレッド オブジェクトのオブジェクトに対して assign を呼び出してもよいかどうかわかりません。
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 の実行は、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 でスタック オーバーフローが発生しました。中断モードでの割り当てがスタックを台無しにする可能性があるのか 、それともインディに問題があるのか どうか疑問に思います。マネージド コードとアンマネージド コードが混在しているときに例外がマスクされていない場合、問題が発生する可能性があることをお読みください。これが関係しているかどうかはわかりません。注: 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
スタックオーバーフローを引き起こす実際の問題が何であるか、または例外をキャッチする方法を知っている人はいますか? インディ送信をtry/exceptでラップしましたが、それはスレッドではなくメインプロセスでのみ機能すると思うので、次のコードのように実装したHandleExceptionを呼び出すEventMesssenger.Executeのコードの周りにtry/exceptを追加しました、ただし、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;