德尔福线程异常机制

问题描述 投票:15回答:4

我对线程德尔福是如何工作的,以及为什么在一个时刻,当一个线程应该引发一个异常的困境,这个异常没有显示。波纹管与评论的代码,也许有人CAND给我解释一下该线程,或Delphi,如何管理访问冲突

//线程代码

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.

项目的代码

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.

此应用程序的目的是只知道在哪里访问冲突逮住,代码应该怎么写。 我无法理解为什么在线“a [2]:=‘dbwdbkbckbk’;”该AV不提高。

multithreading delphi exception-handling
4个回答
20
投票

2005年,德尔福 - 也许大多数其他版本 - 如果有异常从Execute方法逃脱而没有被处理,那么它会被调用Execute并存储在线程的FatalException属性的函数捕获。 (看看Classes.pas,ThreadProc。)没有进一步与该异常,直到线程被释放,在这一点异常也被释放完成。

这是你的责任,因此,检查物业,并做一些事情。您可以在线程的OnTerminate处理程序进行检查。如果它不为空,则线程终止由于未捕获到异常。因此,举例来说:

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;

有没有必要为您跟踪线程数的互锁功能。无论您的线程创建函数和您的终止处理程序总是在主线程的上下文中运行。普通的旧IncDec就足够了。


12
投票

线程是一个地方,你应该吞例外。

在线程处理异常的要点是,如果你想在异常被显示给最终用户,你应该抓住它,并把它传递到哪里可以安全地显示在主线程。

你会发现在这个EDN线程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;

0
投票

我们还可以再加注FatalException。 Reraising似乎不符合逻辑的,但如果你在你的代码有一个中央异常/错误处理程序和,如果你只是想包括线程例外成机理探讨,你可以在某些罕见的情况再次加注:

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;

0
投票

“一”变量未初始化!它可以指出您的计算机的任何可能的存储位置。它甚至可以指向物理上不存在(即使是没有实际意义,由于虚拟内存系统)的位置。

所以,在你的程序中,如果“A”点是偶然在一个有效的内存地址(我的意思是进程拥有的地址),那么你的代码将在该位置没有写访问冲突。我想你至少应该把“a”到NIL。

在这里看到雷米勒博的评论:http://www.stackoverflow.com/a/16071764/46207 这也:Why uninitialized pointers cause mem access violations close to 0?

© www.soinside.com 2019 - 2024. All rights reserved.