Jef*_*eff 8 delphi multithreading exception raise tthread
我刚刚意识到我的异常没有在我的线程中向用户显示!
起初我在我的线程中使用它来引发异常,这不起作用:
except on E:Exception do
begin
raise Exception.Create('Error: ' + E.Message);
end;
Run Code Online (Sandbox Code Playgroud)
IDE向我显示了异常,但我的应用程序没有!
我四处寻找解决方案,这就是我发现的:
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22039681.html
这些都不适合我.
这是我的Thread单元:
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.
Run Code Online (Sandbox Code Playgroud)
如果您需要更多信息,请告诉我.
再次:IDE捕获所有异常,但我的程序没有显示它们.
编辑:Cosmin的解决方案最终起作用 - 而且它最初没有的原因是因为我没有添加ErrMsg变量,而是我只是将变量包含的任何内容放入Synchronize中,这将不起作用,但我不明白为什么.当我没有其他想法时我才意识到这一点,我只是搞砸了解决方案.
一如既往,这个笑话就在我身上.= P
Dis*_*ned 13
您需要了解有关多重开发的一些非常重要的事情:
每个线程都有自己的调用堆栈,几乎就像它们是独立的程序一样.这包括程序的主线程.
线程只能以特定方式相互交互:
注意:请注意,线程不能严格地直接调用其他线程.例如,如果线程A试图直接调用线程B,那么这将是线程A的调用堆栈的一个步骤!
这将我们带到问题的主题:"我的帖子中没有提出异常"
原因是所有例外情况都是:
因此,TThread不会自动向您的主应用程序报告异常.
您必须明确决定如何处理线程中的错误,并相应地实现.
TIP: Make sure the exception doesn't escape the thread. The OS won't like you if it does.编辑:指示要求的代码示例.
如果您只想通知用户,那么Cosmind Prund的答案 应该适用于Delphi 2010.旧版本的Delphi需要更多的工作.以下概念上类似于杰夫自己的答案,但没有错误:
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;
Run Code Online (Sandbox Code Playgroud)
关于杰夫自己答案的一些重要更正,包括他的问题中显示的实施:
Terminate只有当你的线程在while not Terminated do...循环中实现时,调用才有意义.看看这个Terminate方法实际上做了什么.
打电话Exit是不必要的浪费,但你可能因为你的下一个错误而这样做了.
在您的问题中,您将自己包装每个步骤try...except来处理异常.这绝对不是不行!通过这样做,你假装即使发生了异常,一切都还可以.你的线程尝试下一步,但实际上保证失败!这不是处理异常的方法!
这是我对这个问题非常非常简短的"接受".它仅适用于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;
Run Code Online (Sandbox Code Playgroud)
线程不会自动将异常传播到其他线程.所以你必须自己处理它.
拉斐尔概述了一种方法,但也有其他选择.解决方案Rafael指出通过将其编组到主线程中来同步处理异常.
在我自己使用线程的一个线程池中,线程捕获并接管异常的所有权.这允许控制线程随意处理它们.
代码看起来像这样.
procedure TMyThread.Execute;
begin
Try
DoStuff;
Except
on Exception do begin
FExceptAddr := ExceptAddr;
FException := AcquireExceptionObject;
//FBugReport := GetBugReportCallStackEtcFromMadExceptOrSimilar.
end;
End;
end;
Run Code Online (Sandbox Code Playgroud)
如果控制线程选择引发异常,它可以这样做:
raise Thread.FException at Thread.FExceptAddr;
Run Code Online (Sandbox Code Playgroud)
有时你可能有代码不能调用Synchronize,例如一些DLL,这种方法很有用.
请注意,如果您没有引发捕获的异常,则需要将其销毁,否则会发生内存泄漏.
| 归档时间: |
|
| 查看次数: |
4033 次 |
| 最近记录: |