Delphi thread exception mechanism

http://www.techques.com/question/1-3627743/Delphi-thread-exception-mechanism

i have a dilema on how threads work in delphi, and why at a moment when a thread should raise an exception,

the exception is not showed. bellow is the code with comments, maybe somebody cand explain to me how that thread,

or delphi, is managing access violations

//thread code

unit Unit2;

interface

uses
  Classes,
  Dialogs,
  SysUtils,
  StdCtrls;

type
  TTest = class(TThread)
  private
  protected
    j: Integer;
    procedure Execute; override;
    procedure setNr;
  public
    aBtn: tbutton;
  end;

implementation

{ TTest }

procedure TTest.Execute;
var
  i                 : Integer;
  a                 : TStringList;
begin
 // make severals operations only for having something to do
  j := 0;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;
  for i := 0 to 100000000 do
    j := j + 1;

  Synchronize(setnr);
  a[2] := ‘dbwdbkbckbk‘; //this should raise an AV!!!!!!

end;

procedure TTest.setNr;
begin
  aBtn.Caption := IntToStr(j)
end;

end.

project‘s code

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,
  Unit2, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
  public
    nrthd:Integer;
    acrit:TRTLCriticalSection;
    procedure bla();
    procedure bla1();
    function bla2():boolean;
    procedure onterm(Sender:TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.bla;
begin
 try
  bla1;
 except on e:Exception do
   ShowMessage(‘bla ‘+e.Message);
 end;
end;

procedure TForm1.bla1;
begin
 try
  bla2
 except on e:Exception do
   ShowMessage(‘bla1 ‘+e.Message);
 end;
end;

function TForm1.bla2: boolean;
var ath:TTest;
begin
 try
  ath:=TTest.Create(true);
   InterlockedIncrement(nrthd);
  ath.FreeOnTerminate:=True;
  ath.aBtn:=Button1;
  ath.OnTerminate:=onterm;
   ath.Resume;
 except on e:Exception do
  ShowMessage(‘bla2 ‘+e.Message);
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);

begin
//
 try
   bla;
   while nrthd>0 do
    Application.ProcessMessages;
 except on e:Exception do
  ShowMessage(‘Button1Click ‘+e.Message);
 end;
 ShowMessage(‘done with this‘);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 nrthd:=0;
end;

procedure TForm1.onterm(Sender: TObject);
begin
 InterlockedDecrement(nrthd)
end;

end.

the purpose of this application is only to know where the access violation is catch, and how the code should be written.
i can not understand why in the line "a[2] := ‘dbwdbkbckbk‘;" the AV is not raised.

thanks in advance and best regards!

hreading is one place where you should swallow exceptions.

The gist of handling Exceptions in threads is that if you want the exception to be shown to the end user,

you should capture it and pass it on to the main thread where it can safely be shown.

You‘ll find some examples in this EDN thread How to Handle exceptions in TThread Objects.

procedure TMyThread.DoHandleException;
begin
  // Cancel the mouse capture
  if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  // Now actually show the exception
  if FException is Exception then
    Application.ShowException(FException)
  else
    SysUtils.ShowException(FException, nil);
end;

procedure TMyThread.Execute;
begin
  FException := nil;
  try
    // raise an Exception
    raise Exception.Create(‘I raised an exception‘);
  except
    HandleException;
  end;
end;

procedure TMyThread.HandleException;
begin
  // This function is virtual so you can override it
  // and add your own functionality.
  FException := Exception(ExceptObject);
  try
    // Don‘t show EAbort messages
    if not (FException is EAbort) then
      Synchronize(DoHandleException);
  finally
    FException := nil;
  end;
end;

In Delphi 2005 — and probably most other versions — if an exception escapes from the Execute method without being handled,

then it is caught by the function that called Execute and stored in the thread‘s FatalException property.

(Look in Classes.pasThreadProc.)

Nothing further is done with that exception until the thread is freed, at which point the exception is also freed.

It‘s your responsibility, therefore, to check that property and do something about it.

You can check it in the thread‘s OnTerminate handler.

If it‘s non-null, then the thread terminated due to an uncaught exception. So, for example:

procedure TForm1.onterm(Sender: TObject);
var
  ex: TObject;
begin
  Assert(Sender is TThread);
  ex := TThread(Sender).FatalException;
  if Assigned(ex) then begin
    // Thread terminated due to an exception
    if ex is Exception then
      Application.ShowException(Exception(ex))
    else
      ShowMessage(ex.ClassName);
  end else begin
    // Thread terminated cleanly
  end;
  Dec(nrthd);
end;

We can also reraise FatalException.

Reraising seems not logical but if you have an central exception/error handler in your code and

and if you just want to include thread exceptions into that mechanisim, you can reraise on some rare situation :

procedure TForm1.onterm(Sender: TObject);
var
  ex: Exception;
begin
  Assert(Sender is TThread);
  ex := Exception(TThread(Sender).FatalException);
  if Assigned(ex) then
    // Thread terminated due to an exception
    raise ex;
  Dec(nrthd);
end;

How to handle exceptions in TThread objects

By: Corbin Dunn

Abstract: This document describes how to properly handle and show an exception that happens in a thread.

Question: 
I have a TThread object which may raise an exception in the Execute procedure.

When an exception is raised, I want to be able to show that exception to the end user.

How do I go about doing this in the most efficient way?

Answer:
With a TThread object, if you don‘t catch an exception in the Execute procedure of a TThread,

you may get access violations.

The Delphi IDE may break fine on the exception, but often when the application is run outside of the IDE

you get an "Application error has occurred" exception and your application stops running.

If you don‘t care about showing the end user that an exception occurred,

you can simply wrap your Execute procedure with a try..finally block such as:

procedure TMyThread.Execute;
begin
  try
    // Do your thread stuff here
  except // Eat all exceptions
  end;
end;

Quite often, this isn‘t the best solution and you will want to show the message to the end user,

or allow your application to further process the message.

The easiest way to do this, is to add an Exception object to your TThread class,

and call the appropriate handler based on the type of exception.

Here is an example of how to do this.

The project consists of one form with a Button placed on it:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes,
  Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyThread = class(TThread)
  private
    FException: Exception;
    procedure DoHandleException;
  protected
    procedure Execute; override;
    procedure HandleException; virtual;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TMyThread.DoHandleException;
begin
  // Cancel the mouse capture
  if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  // Now actually show the exception
  if FException is Exception then
    Application.ShowException(FException)
  else
    SysUtils.ShowException(FException, nil);
end;

procedure TMyThread.Execute;
begin
  FException := nil;
  try
    // raise an Exception
    raise Exception.Create(‘I raised an exception‘);
  except
    HandleException;
  end;
end;

procedure TMyThread.HandleException;
begin
  // This function is virtual so you can override it
  // and add your own functionality.
  FException := Exception(ExceptObject);
  try
    // Don‘t show EAbort messages
    if not (FException is EAbort) then
      Synchronize(DoHandleException);
  finally
    FException := nil;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Create an instance of the TMyThread
  with TMyThread.Create(True) do
  begin
    FreeOnTerminate := True;
    Resume;
  end;
end;

end.

vv

时间: 2024-10-06 09:36:13

Delphi thread exception mechanism的相关文章

delphi.thread.线程循环执行体结构

线程话题太大,又都是些坑,不知从哪方面讲起,所以,想一出是一出了. 不管怎样,我们从开始使用D,不管有没有用线程,其实它已经帮我们做了一个最完整的线程执行处理:Application.Run. 这行App.Run,在dpr,想来各位都经常能够看到,如果跟踪下去,我们就会发现,它其实就是一个最完整的线程执行体的结构了: 我将里面一些代码删除掉了,再将HandleMessage的代码复制过来,然后,代码如下: procedure TApplication.Run; var Msg: TMsg; be

delphi.thread.同步

注意:此文只是讲线程间的同步,其它同步不涉及. 线程同步是个好话题,因为写线程经常会遇到,所以就写写自己知道的东西. D里面,同步(特指线程同步)从线程的角度来分,有几种情况: 1:主线程与工作线程的同步 2:工作线程与主线程的同步 3:工作线程之间的同步. 同步,嗯,直白点讲,或可以说成是:A线程怎么通知B线程去做某某事,或者说某事需要:如何控制某一时间段内,A能做,B不能做(互斥). 所以,手段很重要,也就有了API,也就有了方法: 1:lock(CriticalSection) 2:Eve

Delphi之Exception获得错误信息

相关资料: http://www.cnblogs.com/hackpig/archive/2010/02/15/1668547.html 实例代码: 1 unit Unit1; 2 3 interface 4 5 uses 6 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 7 Dialogs, StdCtrls; 8 9 type 10 TForm1 = class(TForm) 11 But

Delphi DLL制作和加载 Static, Dynamic, Delayed 以及 Shared-Memory Manager

一 Dll的制作一般分为以下几步:1 在一个DLL工程里写一个过程或函数2 写一个Exports关键字,在其下写过程的名称.不用写参数和调用后缀.二 参数传递1 参数类型最好与window C++的参数类型一致.不要用DELPHI的数据类型.2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态.成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容.3 用stdcall声明后缀.4 最好大小写敏感.5 无须用far调用后缀,那只是为了与windows 1

Android Non-UI to UI Thread Communications(Part 1 of 5)

original:http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/ ANDROID UI THREAD AND ANR On the Android platform, applications operate, by default, on one thread.  This thread is called the UI thread.  It is often call

.Net下Unhandled Exception的捕获

C# 处理unhandled Exception方式如下:1.    在程序的Main()方法中增加如下代码.      //处理线程未处理的异常   Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);   //处理系统未处理的异常    AppDomain.CurrentDomain.UnhandledException +=

AttributeError: &#39;module&#39; object has no attribute &#39;Thread&#39;

$ python thread.py starting at: 2015-08-05 00:24:24Traceback (most recent call last):  File "thread.py", line 28, in <module>    main()  File "thread.py", line 16, in main    th = threading.Thread(target= test,args= (i,2))Attribu

Objective-C try/catch异常处理机制原理。

http://www.cnblogs.com/markhy/p/3169035.html Objective-C使用@try @catch @finally来捕获并处理异常.处理异常需要用到NSException类,它是所有异常的基类.你可以直接使用NSException类来捕获异常,也可以继承一个新的类. Objective-C是C语言的扩充,它的异常处理机制是通过C标准库提供两个特殊的函数setjmp()和longjmp()函数实现的.如果对C的异常处理机制和setjmp.longjmp函数

spring security 学习文档

web service Prepared by:   Sea                                                                                                                                                            29 April, 2018 Contents 1.             The description of spring