Delphi线程异常机制 [英] Delphi thread exception mechanism

查看:303
本文介绍了Delphi线程异常机制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在delphi中有一个线程工作的困境,为什么在一个线程应该引发异常的时候,这个异常没有显示出来。 bellow是带有评论的代码,也许有人可以向我解释这个线程或者delphi是如何管理访问冲突的。



//线程代码

$ b $单位Unit2; b

  unit Unit2; 

接口

使用
类,
对话框,
SysUtils,
StdCtrls;

type
TTest = class(TThread)
private
protected
j:Integer;
程序执行;覆盖
procedure setNr;
public
aBtn:tbutton;
结束

执行


{TTest}

程序TTest.Execute;
var
i:整数;
a:TStringList;
begin
//仅对某些操作进行操作
j:= 0;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0 to 100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;
for i:= 0到100000000 do
j:= j + 1;

同步(setnr);
a [2]:='dbwdbkbckbk' //这应该提高AV !!!!!!

end;

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

结束。

项目代码

 code> unit Unit1; 

接口

使用
Windows,消息,SysUtils,变体,类,图形,控件,表单,
对话框,
Unit2, StdCtrls;

type
TForm1 = class(TForm)
Button1:TButton;
procedure Button1Click(Sender:TObject);
procedure FormCreate(Sender:TObject);
private
public
nrthd:整数;
acrit:TRTLCriticalSection;
procedure bla();
procedure bla1();
函数bla2():boolean;
procedure onterm(Sender:TObject);
结束

var
Form1:TForm1;

执行

{$ R * .dfm}

程序TForm1.bla;
begin
try
bla1;
除了e:Exception do
ShowMessage('bla'+ e.Message);
结束
结束

procedure TForm1.bla1;
begin
try
bla2
除了e:Exception do
ShowMessage('bla1'+ e.Message);
结束
结束

函数TForm1.bla2:boolean;
var ath:TTest;
begin
try
ath:= TTest.Create(true);
InterlockedIncrement(nrthd);
ath.FreeOnTerminate:= True;
ath.aBtn:= Button1;
ath.OnTerminate:= onterm;
运动员
除了e:Exception do
ShowMessage('bla2'+ e.Message);
结束
结束

procedure TForm1.Button1Click(Sender:TObject);

begin
//
try
bla;
而nrthd> 0 do
Application.ProcessMessages;
除了e:Exception do
ShowMessage('Button1Click'+ e.Message);
结束
ShowMessage('done with this');
结束

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

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

结束。

此应用程序的目的只是为了知道访问冲突的捕获位置,以及代码应该如何被写入。

我不明白为什么在行a [2]:='dbwdbkbckbk'; AV不提高

解决方案

在Delphi 2005中 - 可能大多数其他版本 - 如果异常从执行方法没有被处理,那么它被调用 Execute 并存储在线程的 FatalException 属性。 (查看 Classes.pas ThreadProc 。)除非线程被释放,否则没有任何进一步的处理,此时异常也是释放。



因此,您有责任检查该物业并对此进行处理。您可以在线程的 OnTerminate 处理程序中查看它。如果它是非空的,则线程由于未捕获的异常而终止。所以,例如:

  procedure TForm1.onterm(Sender:TObject); 
var
ex:TObject;
begin
Assert(发件人为TThread);
ex:= TThread(Sender).FatalException;
如果分配(ex)然后开始
//由于异常导致线程终止
如果ex是Exception然后
Application.ShowException(Exception(ex))
else
ShowMessage(ex.ClassName);
end else begin
//线程终止干净
end;
Dec(nrthd);
结束

不需要联锁功能来跟踪线程数。您的线程创建功能和终止处理程序都始终在主线程的上下文中运行。 c> c Dec 已经足够了。


I have a dilemma 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 catched, and how the code should be written.
I can not understand why in the line "a[2] := 'dbwdbkbckbk';" the AV is not raised.

解决方案

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.pas, ThreadProc.) 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;

There's no need for the interlocked functions for tracking your thread count. Both your thread-creation function and your termination handler always run in the context of the main thread. Plain old Inc and Dec are sufficient.

这篇关于Delphi线程异常机制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆