我刚刚意识到我的异常并没有在我的线程中显示给用户!
一开始,我在线程中使用它来引发异常,但这并不起作用:
except on E:Exception do
begin
raise Exception.Create('Error: ' + E.Message);
end;IDE会向我显示异常,但我的应用程序不会!
我四处寻找解决方案,这是我发现的:
Delphi thread exception mechanism
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22039681.html
这两种方法对我都不起作用。
这是我的线程单元:
unit uCheckForUpdateThread;
interface
uses
Windows, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP, GlobalFuncs, Classes, HtmlExtractor, SysUtils, Forms;
type
TUpdaterThread = class(TThread)
private
FileGrabber : THtmlExtractor;
HTTP : TIdHttp;
AppMajor,
AppMinor,
AppRelease : Integer;
UpdateText : string;
VersionStr : string;
ExceptionText : string;
FException: Exception;
procedure DoHandleException;
procedure SyncUpdateLbl;
procedure SyncFinalize;
public
constructor Create;
protected
procedure HandleException; virtual;
procedure Execute; override;
end;
implementation
uses
uMain;
{ TUpdaterThread }
constructor TUpdaterThread.Create;
begin
inherited Create(False);
end;
procedure TUpdaterThread.Execute;
begin
inherited;
FreeOnTerminate := True;
if Terminated then
Exit;
FileGrabber := THtmlExtractor.Create;
HTTP := TIdHTTP.Create(nil);
try
try
FileGrabber.Grab('http://jeffijoe.com/xSky/Updates/CheckForUpdates.php');
except on E: Exception do
begin
UpdateText := 'Error while updating xSky!';
ExceptionText := 'Error: Cannot find remote file! Please restart xSky and try again! Also, make sure you are connected to the Internet, and that your Firewall is not blocking xSky!';
HandleException;
end;
end;
try
AppMajor := StrToInt(FileGrabber.ExtractValue('AppMajor[', ']'));
AppMinor := StrToInt(FileGrabber.ExtractValue('AppMinor[', ']'));
AppRelease := StrToInt(FileGrabber.ExtractValue('AppRelease[[', ']'));
except on E:Exception do
begin
HandleException;
end;
end;
if (APP_VER_MAJOR < AppMajor) or (APP_VER_MINOR < AppMinor) or (APP_VER_RELEASE < AppRelease) then
begin
VersionStr := Format('%d.%d.%d', [AppMajor, AppMinor, AppRelease]);
UpdateText := 'Downloading Version ' + VersionStr;
Synchronize(SyncUpdateLbl);
end;
finally
FileGrabber.Free;
HTTP.Free;
end;
Synchronize(SyncFinalize);
end;
procedure TUpdaterThread.SyncFinalize;
begin
DoTransition(frmMain.TransSearcher3, frmMain.gbLogin, True, 500);
end;
procedure TUpdaterThread.SyncUpdateLbl;
begin
frmMain.lblCheckingForUpdates.Caption := UpdateText;
end;
procedure TUpdaterThread.HandleException;
begin
FException := Exception(ExceptObject);
try
Synchronize(DoHandleException);
finally
FException := nil;
end;
end;
procedure TUpdaterThread.DoHandleException;
begin
Application.ShowException(FException);
end;
end.如果您需要更多信息,请让我知道。
再说一次: IDE捕获所有异常,但我的程序不显示它们。
编辑:它是Cosmin的解决方案,最终起作用了--一开始没有起作用的原因,是因为我没有添加ErrMsg变量,而是将变量包含的任何内容放入同步中,这是不起作用的,但是我不知道为什么。当我没有其他想法时,我意识到了这一点,我只是胡乱摆弄解决方案。
一如既往,笑话都在我身上。=P
发布于 2011-03-27 00:41:33
这是我在这个问题上非常非常简短的“观点”。它只适用于Delphi 2010+ (因为该版本引入了匿名方法)。与已经发布的更复杂的方法不同,我的方法只显示错误消息,没有更多,也没有更少。
procedure TErrThread.Execute;
var ErrMsg: string;
begin
try
raise Exception.Create('Demonstration purposes exception');
except on E:Exception do
begin
ErrMsg := E.ClassName + ' with message ' + E.Message;
// The following could be all written on a single line to be more copy-paste friendly
Synchronize(
procedure
begin
ShowMessage(ErrMsg);
end
);
end;
end;
end;发布于 2011-03-27 01:27:11
关于多线程开发,你需要了解一些非常重要的事情:
每个线程都有自己的调用堆栈,就像它们是独立的程序一样,几乎是的。这包括你的程序的主线程。
线程之间只能以特定的方式进行交互:
NB:请注意,严格地说,线程不能直接调用其他线程。例如,如果线程A试图直接调用线程B,那么这将是线程A调用堆栈上的一个步骤!
这就把我们带到了这个问题的主题:“在我的线程中没有抛出异常”
这样做的原因是,异常所做的一切都是:
因此,TThread不会向主应用程序automatically报告异常。
您必须明确地决定您希望如何处理线程中的错误,并相应地实现。
解决方案
一旦决定了这一点,实现适当的执行handler.
TIP: Make sure the exception doesn't escape the thread. The OS won't like you if it does.
时将立即报告错误
编辑:指定需求的代码示例。
如果你想要做的就是通知用户,那么Cosmind Prund's answer在Delphi2010上应该能完美地工作。老版本的Delphi需要做更多的工作。以下代码在概念上类似于Jeff's own answer,但没有错误:
procedure TUpdaterThread.ShowException;
begin
MessageDlg(FExceptionMessage, mtError, [mbOk], 0);
end;
procedure TUpdaterThread.Execute;
begin
try
raise Exception.Create('Test Exception');
//The code for your thread goes here
//
//
except
//Based on your requirement, the except block should be the outer-most block of your code
on E: Exception do
begin
FExceptionMessage := 'Exception: '+E.ClassName+'. '+E.Message;
Synchronize(ShowException);
end;
end;
end;对Jeff自己的答案进行了一些重要的更正,包括他的问题中显示的实现:
只有当您的线程在while not Terminated do中实现时,对Terminate的调用才是相关的……循环。看一看Terminate方法的实际作用。
调用Exit是一种不必要的浪费,但您这样做可能是因为您的下一个错误。
在您的问题中,您将每个步骤包装在其自己的try...except中以处理异常。这是一个的绝对禁忌!通过这样做,您可以假装即使发生了异常,一切都是正常的。您的线程尝试下一步,但实际上肯定会失败!这是而不是处理异常的方式!
发布于 2011-03-26 23:00:22
线程不会自动将异常传播到其他线程中。所以你必须自己处理它。
Rafael概述了一种方法,但也有替代方法。Rafael指出的解决方案是通过将异常编组到主线程中来同步处理异常。
在我自己对线程的一个使用中,线程池,线程捕获并接管异常的所有权。这允许控制线程随心所欲地处理它们。
代码如下所示。
procedure TMyThread.Execute;
begin
Try
DoStuff;
Except
on Exception do begin
FExceptAddr := ExceptAddr;
FException := AcquireExceptionObject;
//FBugReport := GetBugReportCallStackEtcFromMadExceptOrSimilar.
end;
End;
end;如果控制线程选择引发异常,它可以这样做:
raise Thread.FException at Thread.FExceptAddr;有时你的代码可能无法调用同步,例如一些DLL,这种方法很有用。
请注意,如果不引发捕获的异常,则需要销毁该异常,否则会发生内存泄漏。
https://stackoverflow.com/questions/5442978
复制相似问题