您的位置:首页 > 编程语言 > Delphi

在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!

2012-11-05 09:37 399 查看
在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!

  如果直接使用Win32的API函数CreateThread()创建多个线程,也是可以创建的。但是,你应该明白,在每个线程中动态分配和销毁内存块,是需要同步保护的。Delphi语言中有一个在使用多线程环境下至关重要的全局变量IsMultiThread,系统在进行内存分配的时候,根据IsMultiThread变量值判断当前是否使用在多线程环境下,如果该变量为True,哪么,系统在分配和销毁内存的时候,是要进行同步保护的。相反,则不用同步保护。

  所以,如果你直接使用CreateThread()创建线程,一定要记得手动将IsMultiThread变量置为True。要不然你就会经常发现系统内存非法访问错误!如果你使用Delphi中的BeginThread()创建线程,这个BeginThread()的实现如下:

function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;

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;

  看见了吗?上面已经将IsMultiThread := TRUE;这样就保证了在多线程下,内存使用的安全。

  使用BeginThread()函数替代CreateThread()的另一个重要理由就在上面的的代码段中,你发现了吗?BeginThread()函数内部在调用CreateThread()的时候,哪个线程函数指针用的是@ThreadWrapper,参数用的是P,而 P: PThreadRec; 是一个结构体指针,结构体内部分别才是线程函数和线程函数参数。

  ThreadWrapper函数实现如下:

{$IFDEF MSWINDOWS}

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 marker }

ADD ESP, 4

{$ENDIF}

end;

  ThreadWrapper函数是使用BASM汇编代码实现,如果你熟悉BASM汇编,你就知道,前面的代码,是BASM汇编中函数传参数的约定,后面的才是重点,它内部实现了当执行线程函数出现异常错误时,转化为异常的机制。

  如果你直接使用CreateThread()创建线程,当然就不会有执行线程函数提供触发异常这样的好处,这才是使用BeginThread()函数替代CreateThread()的最重要原因,也是根本原因。

  线程中的异常机制很重要吗?当然重要!因为线程函数只是一个执行函数过程体,当在这个函数的执行过程中,如果发生异常,程序就会退出当前线程函数,也就是线程会终止。所以在线程中提供异常机制,并让我们在线程中可以捕获处理,是非常至关重要的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: