CreateThread()函数及_beginthreadex()函数

CreateThread():创建一个线程可以调用进程的虚拟地址空间内执行。创建的线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。

函数原型:

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  SIZE_T                  dwStackSize,
  LPTHREAD_START_ROUTINE  lpStartAddress,
  __drv_aliasesMem LPVOID lpParameter,
  DWORD                   dwCreationFlags,
  LPDWORD                 lpThreadId
);

参数解释:
lpThreadAttributes
指向SECURITY_ATTRIBUTES 结构的指针,该结构确定子进程是否可以继承返回的句柄。如果 lpThreadAttributes为NULL,则不能继承该句柄。
结构的lpSecurityDescriptor成员为新线程指定一个安全描述符。如果lpThreadAttributes为NULL,则线程获取默认的安全描述符。线程的默认安全描述符中的ACL来自创建者的主要令牌。
dwStackSize
堆栈的初始大小,以字节为单位。系统将此值舍入到最接近的页面。如果此参数为零,则新线程将使用可执行文件的默认大小。有关更多信息,请参见 线程堆栈大小。
lpStartAddress
指向要由线程执行的应用程序定义的函数的指针。该指针表示线程的起始地址。有关线程函数的更多信息,请参见 ThreadProc。
lpParameter
指向要传递给线程的变量的指针。
dwCreationFlags
控制线程创建的标志。

含义
0 线程在创建后立即运行
CREATE_SUSPENDED 该线程以挂起状态创建,并且直到调用ResumeThread函数后才运行 。
STACK_SIZE_PARAM_IS_A_RESERVATION 所述dwStackSize参数指定堆栈的初始保留大小。如果未指定此标志,则dwStackSize指定提交大小。

lpThreadId
指向接收线程标识符的变量的指针。如果此参数为 NULL,则不返回线程标识符。


返回值

如果函数成功,则返回值是新线程的句柄。
如果函数失败,则返回值为NULL。可以调用GetLastError函数查看错误


创建示例
...//初始化函数

//线程函数
DWORD WINAPI THreadFun(LPVOID lpParameter)
{
	for(int i = 0;i < 5;++i){
		cout << "子进程:i=" << i << endl;
		Sleep(100);
	}
	return 0;
}
int main()
{
	//创建线程 thread保存线程的句柄
	HANDLE thread = CreateThread(NULL,0,THreadFun,NULL,0,NULL);
	//关闭线程
	CloseHandle(thread);
}


_beginthreadex():用于创建一个线程。CreateThread()函数时Windows提供的API接口,但是在C/C++语言中使用_beginthreadex()创建函数。标准C运行库与多线程存在矛盾。Windows提供解决矛盾的办法每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而这块内存区域的创建由_beginthreadex()来负责。

函数原型:

uintptr_t _beginthreadex( // NATIVE CODE
   void *security,
   unsigned stack_size,
   unsigned ( __stdcall *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr
);

参数解释:
security
安全属性,为NULL时表示默认安全。
start_address
开始执行新线程的例程的起始地址。对于_beginthread,调用约定是__cdecl(对于本机代码)或__clrcall(对于托管代码);对于_beginthreadex,它可以是__stdcall(对于本机代码)或__clrcall(对于托管代码)。

/*函数执行成功返回新线程句柄,失败返回0
*_stdcall表示:1、参数从右向左压入堆栈
*              2、函数被调用者修改堆栈
*/

stack_size
新线程的堆栈大小,或为0。
arglist
要传递给新线程的参数列表,或者为NULL。
指向SECURITY_ATTRIBUTES结构的安全指针,该结构确定返回的句柄是否可以由子进程继承。如果Security为NULL,则不能继承该句柄。对于Windows 95应用程序,必须为NULL。
initflag
用于控制新线程的初始状态的标志。将initflag设置为0可立即运行,或将CREATE_SUSPENDED设置为处于挂起状态的线程;使用ResumeThread执行线程。将initflag设置为STACK_SIZE_PARAM_IS_A_RESERVATION标志,以使用stack_size作为堆栈的初始保留大小(以字节为单位);如果未指定此标志,则stack_size指定提交大小。
thrdaddr
指向接收线程标识符的32位变量。如果为NULL,则不使用。


返回值

如果成功,每个函数都返回一个新创建线程的句柄;但是,如果新创建的线程退出得太快,_beginthread可能不会返回有效的句柄。如果有错误,_beginthread返回-1L,如果线程太多,errno设置为EAGAIN,如果参数无效或堆栈大小不正确,设置为EINVAL,或者如果资源不足(比如内存),设置为EACCES。当发生错误时,_beginthreadex返回0,设置errno和_doserrno。


创建示例:

...//初始化函数

unsgined int _stdcall ThreadFun(PVOID pM)
{
    //实现代码
    reuturn 0;
}
int main()
{
    HANDLE hand;
    handl = (HANDLE)_beginthreadex(NULL,0,ThreadFun,Null,0,NULL);
    WaitFOrSingleObject(ThreadFun,INFINTE);
    //代码实现
    return 0;
}


可执行文件中的调用C运行时库(CRT)的线程应将_beginthreadex和_endthreadex函数用于线程管理,而不是 CreateThread和 ExitThread;这需要使用CRT的多线程版本。如果使用CreateThread创建的线程调用CRT,则CRT可能会在内存不足的情况下终止进程。

上一篇:循环队列的实现


下一篇:java – 何时在Spring中使用Hibernate的事务?