unit UnitMain;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
function threadfunc(StartPos: pointer):integer ;stdcall; //
implementation{$R *.dfm}function threadfunc(StartPos: pointer):integer ;stdcall; //
var
s,i:integer;
begin
i:=0;
try
s := s div i;
except end;
end ;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
cThreadId,cThreadId2 :cardinal;
begin
beginthread(nil,1024,@threadfunc2,nil,0,cThreadId2);
end;end.如上代码,当我单击运行的时候,程序自动全部退出来,只是线程出现异常怎么 整个程序都退了出来,我设置的 try except 不好用请问各位大侠,我如何在线程里捕获这个异常
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
function threadfunc(StartPos: pointer):integer ;stdcall; //
implementation{$R *.dfm}function threadfunc(StartPos: pointer):integer ;stdcall; //
var
s,i:integer;
begin
i:=0;
try
s := s div i;
except end;
end ;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
cThreadId,cThreadId2 :cardinal;
begin
beginthread(nil,1024,@threadfunc2,nil,0,cThreadId2);
end;end.如上代码,当我单击运行的时候,程序自动全部退出来,只是线程出现异常怎么 整个程序都退了出来,我设置的 try except 不好用请问各位大侠,我如何在线程里捕获这个异常
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons; type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end; var
Form1: TForm1;
function threadfunc(startPos:Pointer):integer ;cdecl;
implementation {$R *.dfm} function threadfunc(startPos:Pointer):integer ;cdecl;
var
s,i:integer;
begin
i:=0;
try
s := s div i;
except
raise;
end;
end ;
procedure TForm1.BitBtn1Click(Sender: TObject);
var
cThreadId,cThreadId2 :cardinal;
begin
beginthread(nil,1024,@threadfunc2,nil,0,cThreadId2);
end; end.
基本上沒有問題,應該調用的方式問題。
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function threadfunc(startPos:Pointer):integer ;cdecl;//stdcall; //
var
Form1: TForm1;
V : Tthread;implementation{$R *.dfm}function threadfunc(startPos:Pointer):integer ;cdecl;
var
s,i:integer;
begin
i:=0;
s := 3;
try
s := s div i;
Result := s; // 還有這裏,不管怎麼樣,如果你一定想測這個異常,就加上這個返回代碼,不然讓編譯器優化掉後,即使代碼是有異常但也不會被執行。
except
raise;
end;
end ;procedure TForm1.Button1Click(Sender: TObject);
var
cThreadId,cThreadId2 :cardinal;
begin
cThreadId := beginthread(nil,0,@threadfunc,Pointer(Self),CREATE_SUSPENDED,cThreadId2);
ResumeThread(cThreadId)
end;end.
記住上面的 stacall 轉為 cdecl 或者不要帶
beginthread cdecl 壓棧, 由調用者管理。
ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
var ThreadId: LongWord): Integer;
var
P: PThreadRec;
begin
New(P);
P.Func := ThreadFunc;
P.Parameter := Parameter;
IsMultiThread := TRUE;
Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P, CreationFlags, ThreadID);
end;
其中调用了Windows API函数CreateThread来创建线程。 CreateThread的定义如下:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to thread security attributes
DWORD dwStackSize, // initial thread stack size, in bytes
LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function
LPVOID lpParameter, // argument for new thread
DWORD dwCreationFlags, // creation flags
LPDWORD lpThreadId // pointer to returned thread identifier
);
第三个参数就是线程代码入口地址, LPTHREAD_START_ROUTINE的定义如下:
DWORD WINAPI ThreadFunc( LPVOID );显然:
1. 这个线程函数是一个无参数的函数, (StartPos: pointer)这部分是不能写的,否则会出现异常。
2. 这个线程函数是使用stdcall的调用约定的。
不好意思,的確是看錯了。 應該是想到了 __BeginThread 的影響显然:
1. 这个线程函数是一个无参数的函数, (StartPos: pointer)这部分是不能写的,否则会出现异常。 // 怎麼可能跟它有關呢。呵呵
2. 这个线程函数是使用stdcall的调用约定的。 我只是想到了 cdecl,stacacll 清棧的問題,沒有注意查,保歉
threadFun 是一個:
DWORD WINAPI ThreadProc(
LPVOID lpParameter
);//無類型的定義吧, 即這個參數可以是任何類型。 其實他這個程序最主要的問題就在於:function threadfunc(startPos:Pointer):integer ;cdecl;
var
s,i:integer;
begin
i:=0;
s := 3;
try
s := s div i;
Result := s; // 這句,這句必須有。一個沒有返回值的函數,我想是不會拋出異常的。因為它根本就不執行
except
raise;
end;
end ;
還有一個原因,我個人的理解; startPos:Pointer 這個參數帶上後,加上 stdcall; 就變向指定了,由函數自己清理堆棖,這個無類型參數就成了罪魁禍首了。
但如查你采用 cdecl 就不會出錯,因為調用者也沒有清棧。所以不會出錯。
这样使用VCL提供的多线程也许会安全些
而栈内其实并没有调用时压入的参数,这将会导致栈异常。ThreadFunc如果申明成这样:function threadfunc(startPos:Pointer):integer; cdecl;编译出的代码中, 在ThreadFunc函数返回时不会对栈进行操作, 这是cdecl约定所要求的“参数入/出栈均由调用者负责”,所以不会出现异常。
不过, 还是应该按照DWORD WINAPI ThreadFunc( LPVOID )的约定来写线程函数, 不要带参数(带了也没用,参数并未被赋值), 以免混乱。
function ThreadWrapper(Parameter: Pointer): Integer; stdcall;
{$ELSE}
function ThreadWrapper(Parameter: Pointer): Pointer; cdecl;
{$ENDIF}
asm
{$IFDEF PC_MAPPED_EXCEPTIONS}
{ Mark the top of the stack with a signature }
PUSH UNWINDFI_TOPOFSTACK
{$ENDIF}
CALL _FpuInit
PUSH EBP
{$IFNDEF PC_MAPPED_EXCEPTIONS}
XOR ECX,ECX
PUSH offset _ExceptionHandler
MOV EDX,FS:[ECX]
PUSH EDX
MOV FS:[ECX],ESP
{$ENDIF}
{$IFDEF PC_MAPPED_EXCEPTIONS}
// The signal handling code in SysUtils depends on being able to
// discriminate between Delphi threads and foreign threads in order
// to choose the disposition of certain signals. It does this by
// testing a TLS index. However, we allocate TLS in a lazy fashion,
// so this test can fail unless we've already allocated the TLS segment.
// So we force the allocation of the TLS index value by touching a TLS
// value here. So don't remove this silly call to AreOSExceptionsBlocked.
CALL AreOSExceptionsBlocked
{$ENDIF}
MOV EAX,Parameter MOV ECX,[EAX].TThreadRec.Parameter
MOV EDX,[EAX].TThreadRec.Func
PUSH ECX
PUSH EDX
CALL _FreeMem
POP EDX
POP EAX
CALL EDX{$IFNDEF PC_MAPPED_EXCEPTIONS}
XOR EDX,EDX
POP ECX
MOV FS:[EDX],ECX
POP ECX
{$ENDIF}
POP EBP
{$IFDEF PC_MAPPED_EXCEPTIONS}
{ Ditch our TOS er }
ADD ESP, 4
{$ENDIF}
end;
看過這段沒,匯編不太好,感覺像在處理無類型的參數的。看來DELPHI本身是處理了的。
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
// procedure FormCreate(Sender: TObject);
// procedure Button1Click(Sender: TObject);
//procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;function threadfunc(StartPos: pointer):integer ;stdcall; //
implementation{$R *.dfm}function threadfunc(StartPos: pointer):integer ;stdcall; //
var
s,i:integer;
begin
i:=0;
try
s := s div i;
Result := S;
exceptend;
end ;
procedure TForm1.Button1Click(Sender: TObject);
var
cThreadId,cThreadId2 :cardinal;
begin
CreateThread(nil,1024,@threadfunc,nil,0,cThreadId2); // 不要再用DELPHI封裝的 BeginThread 了,用 Window 的 createThread 就OK了。
end;end.