1、CRT简介:
CRT: (C Runtime Library)即C运行时库,是系统运行的基础,包含了c常用的函数集(如:printf,malloc,strcpy等),为运行main做了初始化环境变量、堆、io等资源,并在结束后清理。
在Windows环境下,VC提供的 C run-time library又分为动态运行时库、静态运行时库、多线程、单线程、调试版本(Debug)、发行版本(Release)等。
2、使用CRT的多线程函数集:两组
3、两组函数的说明:
3.1、_beginthread和_endthread
该函数是C Runtime Library中的函数。其原型如下
unsigned long _beginthread(
void( __cdecl *start_address )( void * ),//线程函数的起始地址
unsigned stack_size,//堆栈大小,设置0为系统默认值
void *arglist );//传递给线程函数的参数,没有则为NULL
“该函数被认为是头脑简单的函数”,使用该函数导致无法有效的控制被创建线程,如不能在启动时将该线程挂起,无法为该线程设置优先权等。另外,无法利用这个Handle来等待该线程结束等操作。该函数是早期的C Runtime Library的产物,不提倡使用,后期的改良版本为_beginthreadex。
通过_beginthread启动的线程在应当通过调用_endthread结束,以保证清除与线程相关的资源。_endthread的原型为:
void _endthread(void);
3.2、_beginthreadex和_endthreadex
该函数是C Runtime Library中的一个函数,用标准C实现,相比_beginthread,_beginthreadex**对线程控制更为有力**(比前者多三个参数),是_beginthread的加强版。其原型为:
unsignedlong _beginthreadex(
void *security,//线程函数的安全描述符
unsigned stack_size,// 堆栈大小,设置0为系统默认值
unsigned ( __stdcall *start_address )( void * ),//线程函数的起始地址
void*arglist, //传递给线程函数的参数,没有则为NULL
unsignedinitflag,//初始状态,0为立即执行,CREATE_SUSPEND为创建后挂起
unsigned*thrdaddr );//指向一个32位的变量,存放线程标识符
该函数返回新线程的句柄,通过该句柄可实现对线程的控制。虽然,该函数是用标准C写的(即可不加修改就可以移植到其他系统执行),但是由于它与Windows系统有着紧密的联系(需要手动关闭该线程产生的Handle),因此实现时,往往需要包含windows.h。
通过_beginthreadex启动的线程通过调用_endthreadex做相关清理。该函数比较像CreateThread函数。
_endthreadex函数的原型为:
void _endthreadex(unsigned retVal);
关于这两组函数的详细区别请参考MSDN的说明:
Creates a thread.
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
);
3.3、线程函数的定义:
_beginthread()和_beginthreadex()的线程执行函数的定义是不一样的。
对于_beginthread()创建的线程,其线程函数定义为:
void ThreadPro(void * pArguments );
对于_beginthreadex()创建的线程,其线程函数定义为:
unsigned __stdcallThreadFunc( void* pArguments )
4、注意事项:
(1)两者创建线程函数方式不同,_beginthreadex()的线程函数必须使用__stdcall调用方式,而且必须返回一个unsigned型的退出码。
(2)_beginthreadex()在创建线程失败时返回0,而_beginthread()在创建线程失败时返回-1,这一点在检测返回结果时必须注意。
(3)如果是调用_beginthread()创建线程,并相应地调用_endthread()结束线程时,系统将自动关闭线程句柄。而调用_beginthreadex()创建线程,并相应地调用_endthreadex()结束线程时,系统不能自动关闭线程句柄。
(4)由于_beginthread()创建线程参数比较简单,不能控制线程的初始启动状态,且不返回创建的线程句柄,也不能调用
WaitForSingleObject()/WaitForMultipleObjects()函数。所以一般不常用,而_beginthreadex()与CreatThread()函数比较相似。能方便控制线程。
注意事项:
(1) 由于_beginthread()创建的线程结束后自动关闭线程句柄,所以不能使用WaitForSingleObject()/WaitForMultipleObjects()函数来同步。
(2) 注意线程函数参数的传递,如果要传递多个参数,可以在创建线程的时候,可以将多个参数封装为一个结构体传递给线程函数。
======================================================
(1) 由于_beginthreadex()创建的线程结束后自动调用_endthreadex()函数,但是不会关闭线程句柄,所以必须手动关闭句柄,但能使用同步函数,如:
WaitForSingleObject()/WaitForMultipleObjects()函数来同步。
(2) 通过该实例还可以稍加改进,就可以统计5个线程的各自的工作时间,并排序。欢迎大家多多练习。
(3) 由_beginthreadex()函数创建线程,能灵和控制和管理线程,所以推荐使用该方式。