多线程编程(二)——_beginthreadex

对于C++运行库,Microsoft的C++运行库为我们提供了2个API函数:
uintptr_t _beginthread(
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist
);
uintptr_t _beginthreadex(
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr
);

对应的,结束线程用:
void _endthread( void );
void _endthreadex(
   unsigned retval
);

现在基本上_beginthreadex和_endthreadex已经完全取代了另外两个函数,从他们的参数就可以看到,_beginthreadex系列函数可以创建具有安全属性的线程,而且还可以让线程挂起,能获得线程的ID。而_endthread被取代的原因是一是他的线程退出代码被硬编码为0,二是在调用         ExitThread之前,会调用CloseHandle,关闭线程的句柄。这样做就会产生一个问题,如下代码中:

DWORD dwExitCode;
HANDLE hThread = _beginthread(…);
GetExitCodeThread(hThread, &dwExitCode);
CloseHandle(hThread);

在第一个线程调用GetExitCodeThread之前,新建的线程有可以已经执行,返回并终止运行了。这个时候,hThread就是无效的,因为_endthread已经关闭了新线程的句柄。所以CloseHandle函数也会失败。

下面一个代码例子来说明他们的用法:

RTThreading.h

#ifndef MULTITHREAD #define MULTITHREAD class DrawPicture { public: static unsigned __stdcall MyThreadFunc(LPVOID lpParam ); void Draw(); private: static int nPoint; }; #endif

RTThreading.CPP

#include <iostream> #include <Windows.h> #include <process.h> #include "RTThreading.h" using namespace std; int DrawPicture::nPoint = 20; unsigned __stdcall DrawPicture::MyThreadFunc( LPVOID lpParam ) { while(nPoint > 0) { cout<<"It is Point:"<<nPoint--<<endl; } //_endthreadex(0); //尽量避免使用,让线程自动正常退出 return 0; } void DrawPicture::Draw() { HANDLE hThread; hThread = (HANDLE)_beginthreadex(NULL, 0, MyThreadFunc, NULL, 0, NULL); CloseHandle(hThread); } int main(void) { DrawPicture *pDraw = new DrawPicture; pDraw->Draw(); delete pDraw; system("pause"); return 0; }

对于Windows SDK API 的CreateThread函数和_beginthreadex,一般调用那一个会更好一点呢?

答案是beginthreadex。从C:/Program Files/Microsoft Visual Studio 9.0/VC/crt/src/threadex.c下的中我们可以看到,_beginthreadex实际上是调用了CreateThread函数,除此之外,他还为每个线程都设有专有_tiddata内存块,传给_beginthreadex的线程函数的地址保存在_tiddata内存块中(这个结构在VC/crt/src/mtdll.h中),C++运行库为主调线程分配并初始化一个_tiddata块,然后这个块会和线程相关联,也就是说,只要线程在运行,我们就可以调用任何的C/C++运行库函数了。

存在的问题一是,如果调用了signal函数,进程就会终止;二是如果不是调用_endthreadex来终止线程,数据块就不会被销毁,从而造成内存泄漏。

对于线程终止和退出,参看多线程编程(一)——CreateThread 和MSDN中的说明。

 

本系列示例代码下载

你可能感兴趣的:(多线程,编程,Microsoft,Security,null,Signal)