关于线程在 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不升高。
4条答案
按热度按时间cfh9epnr1#
在 Delphi 2005中--可能还有大多数其他版本--如果一个异常从
Execute
方法中逃逸而没有被处理,那么它会被调用Execute
的函数捕获,并存储在线程的FatalException
属性中。(在 * Classes.pas *,ThreadProc
中查找。)在线程被释放之前,不会对该异常执行任何操作,此时该异常也被释放。因此,检查该属性并采取措施是您的责任。您可以在线程的
OnTerminate
处理程序中检查它。如果它为非空,则线程由于未捕获的异常而终止。因此,例如:不需要使用互锁函数来跟踪线程计数。线程创建函数和终止处理程序总是在主线程的上下文中运行。简单的
Inc
和Dec
就足够了。jogvjijk2#
线程是您应该接受异常的地方。
在线程中处理异常的要点是,如果您希望向最终用户显示异常,则应捕获它并将其传递到主线程,在主线程中可以安全地显示异常。
您可以在此EDN线程How to Handle exceptions in TThread Objects中找到一些示例。
t40tm48m3#
我们也可以重新引发FatalException。重新引发似乎不合逻辑,但如果您的代码中有一个中央异常/错误处理程序,并且如果您只想将线程异常包含到该机制中,您可以在一些罕见的情况下重新引发:
holgip5t4#
也许你展示的例子并不是最好的,因为变量“a”没有初始化!它可以指向你计算机中任何可能的内存位置。它甚至可以指向物理上不存在的位置(尽管由于虚拟内存系统,这是没有实际意义的)。
所以,在你的程序中,如果“a”意外地指向一个有效的内存地址(我指的是进程拥有的地址),那么你的代码将写入该位置而不会发生访问冲突。我认为你至少应该把“a”设置为NIL。在那之后,看看Lieven Keersmaekers的帖子。
请在此处查看雷米·勒博的评论:http://www.stackoverflow.com/a/16071764/46207
这也是:Why uninitialized pointers cause mem access violations close to 0?