【发布时间】:2018-09-18 15:16:25
【问题描述】:
我有执行匿名线程之类的习惯:
TThread.CreateAnonymousThread(
procedure
begin
.....
end).start;
但问题是,如果在执行过程中会引发一些未处理异常,那么我将不会收到警告!对于主线程,我们有Application.OnException。我们有类似的后台线程吗?
【问题讨论】:
标签: delphi firemonkey
我有执行匿名线程之类的习惯:
TThread.CreateAnonymousThread(
procedure
begin
.....
end).start;
但问题是,如果在执行过程中会引发一些未处理异常,那么我将不会收到警告!对于主线程,我们有Application.OnException。我们有类似的后台线程吗?
【问题讨论】:
标签: delphi firemonkey
TThread 有一个公共的FatalException 属性:
如果
Execute方法引发了一个未在该方法中捕获和处理的异常,则线程终止并将FatalException设置为该异常的异常对象。 应用程序可以从OnTerminate事件处理程序中检查FatalException,以确定线程是否因异常而终止。
例如:
procedure TMyForm.DoSomething;
begin
...
thread := TThread.CreateAnonymousThread(...);
thread.OnTerminate := ThreadTerminated;
thread.Start;
...
end;
procedure TMyForm.ThreadTerminated(Sender: TObject);
begin
if TThread(Sender).FatalException <> nil then
begin
...
end;
end;
【讨论】:
TThread 类时效果很好,但 OP 使用的是 CreateAnonymousThread,所以可能需要指出...
CreateAnonymousThread()。它返回一个暂停的TThread 对象,您可以在调用Start() 之前调整其属性并为其分配事件处理程序
Execute 包裹在 try..except 块中,OnTerminate 与 UI 线程同步。如果您不需要该同步,则可以跳过该事件
N̶o̶,̶̶t̶h̶e̶r̶e̶̶i̶s̶̶n̶o̶t̶h̶i̶n̶g̶̶s̶i̶m̶i̶l̶a̶r̶̶f̶o̶r̶̶a̶̶b̶a̶c̶k̶g̶r̶o̶u̶n̶d̶̶t̶h̶r̶e̶a̶d̶.̶(谢谢,雷米!)
最好的解决方案是始终绝对确保永远不会让异常从线程中逸出。理想情况下,您的线程过程应该如下所示:
TThread.CreateAnonymousThread(
procedure
begin
try
{ your code}
except
{on E : Exception do}
{... handle it!}
end;
end).start;
【讨论】:
好的,我终于得到了最好的答案:
将全局ExceptionAcquired 过程分配给我们自己的实现(默认为nil)。这个过程被调用来处理发生在除主线程之外的其他线程中的未处理异常。
ExceptionAcquired := MyGlobalExceptionAcquiredHandler;
【讨论】:
J... 和 Remy Lebeau 的回答对 delphi 提供的东西很好,但我需要更多,我最终决定对单元进行一些修改System.Classes
var
ApplicationHandleThreadException: procedure (Sender: TObject; E: Exception) of object = nil;
function ThreadProc(const Thread: TThread): Integer;
...
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
if assigned(ApplicationHandleThreadException) and
assigned(Thread.FFatalException) and
(Thread.FFatalException is Exception) and
(not (Thread.FFatalException is EAbort)) then
ApplicationHandleThreadException(Thread, Exception(Thread.FFatalException));
end;
这样你只需要分配ApplicationHandleThreadException 来处理任何TThread 中未处理的异常引发。您不必担心多线程,因为像ExceptAddr 这样的全局变量被声明为threadvar,所以一切正常,甚至检索堆栈跟踪!
【讨论】: