我对线程德尔福是如何工作的,以及为什么在一个时刻,当一个线程应该引发一个异常的困境,这个异常没有显示。波纹管与评论的代码,也许有人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不提高。
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;
有没有必要为您跟踪线程数的互锁功能。无论您的线程创建函数和您的终止处理程序总是在主线程的上下文中运行。普通的旧Inc
和Dec
就足够了。
线程是一个地方,你应该吞例外。
在线程处理异常的要点是,如果你想在异常被显示给最终用户,你应该抓住它,并把它传递到哪里可以安全地显示在主线程。
你会发现在这个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;
我们还可以再加注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;
“一”变量未初始化!它可以指出您的计算机的任何可能的存储位置。它甚至可以指向物理上不存在(即使是没有实际意义,由于虚拟内存系统)的位置。
所以,在你的程序中,如果“A”点是偶然在一个有效的内存地址(我的意思是进程拥有的地址),那么你的代码将在该位置没有写访问冲突。我想你至少应该把“a”到NIL。
在这里看到雷米勒博的评论:http://www.stackoverflow.com/a/16071764/46207 这也:Why uninitialized pointers cause mem access violations close to 0?