Windows线程的创建与终止
线程的创建
CreateThread, AfxBeginThread,_beginthread, _beginthreadex的区别
CreateThread是Windows的API函数,提供操作系统级别的创建线程的操作,且仅限于工作者线程。不调用MFC和RTL的函数时,可以用CreateThread,其它情况不要轻易使用。在使用的过程中要考虑到进程的同步与互斥的关系(防止死锁)。线程函数定义为:DWORD WINAPI ThreadFun(PVOID pParameter)。MSDN:http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx
AfxBeginThread:MFC中线程创建的MFC函数,首先创建了相应的CWinThread对象,然后调用CWinThread::CreateThread,在CWinThread::CreateThread中,完成了对线程对象的初始化工作,然后,调用_beginthreadex(AfxBeginThread相比较更为安全)创建线程。它简化了操作或让线程能够响应消息,即可用于界面线程,也可以用于工作者线程,但要注意不要在一个MFC程序中使用_beginthreadex()或CreateThread()。线程函数定义为:UINT ThreadFun(LPVOID pParam)。MSDN:http://msdn.microsoft.com/en-US/library/s3w9x78e(v=VS.80).aspx
_beginthreadex:MS的C/C++运行期库函数,是对C Runtime库的扩展SDK函数,首先针对C Runtime库做了一些初始化的工作,以保证C Runtime库工作正常。然后,调用CreateThread真正创建线程。MSDN:http://msdn.microsoft.com/en-us/library/kdzttdcb(v=vs.80).aspx
摘自《windows核心编程》:
CreateThread函数是用来创建线程的Windows函数。不过,如果你正在编写C/C++代码,决不应该调用CreateThread。相反,应该使用Visual C++运行期库函数_beginthreadex。如果不使用Microsoft的Visual C++编译器,你的编译器供应商有它自己的CreateThred替代函数。
若要使多线程C和C++程序能够正确地运行,必须创建一个数据结构,并将它与使用C/C++运行期库函数的每个线程关联起来。当你调用C/C++运行期库时,这些函数必须知道查看调用线程的数据块,这样就不会对别的线程产生不良影响。
1.每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构(tiddata结构位于Mtdll.h文件中)。
2.传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。
3._beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。
4.当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr(线程函数地址)来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。
5.如果一切顺利,就会像CreateThread那样返回线程句柄。如果任何操作失败了,便返回NULL。
beginthreadex和_beginthread函数的区别:_beginthread函数的参数比较少,因此比特性全面的_beginthreadex函数受到更大的限制。例如,如果使用_beginthread,就无法创建带有安全属性的新线程,无法创建暂停的线程,也无法获得线程的ID值。
CRT的函数库在线程出现之前就已经存在,所以原有的CRT不能真正支持线程,这导致我们在编程的时候有了CRT库的选择:
对于线程的支持是后来的事!这也导致了许多CRT的函数在多线程的情况下必须有特殊的支持,不能简单的使用CreateThread就OK。大多的CRT函数都可以在CreateThread线程中使用,但并不是所有的都没有问题!
有些CRT的函数象malloc(),fopen(),_open(),strtok(),ctime(),或localtime()等函数需要专门的线程局部存储的数据块,这个数据块通常需要在创建线程的时候就建立,如果使用CreateThread,这个数据块就没有建立,然后会怎样呢?在这样的线程中还是可以使用这些函数而且没有出错,实际上函数发现这个数据块的指针为空时,会自己建立一个,然后将其与线程联系在一起,这意味着如果你用CreateThread来创建线程,然后使用这样的函数,会有一块内存在不知不觉中创建,遗憾的是,这些函数并不将其删除,而CreateThread和ExitThread也无法知道这件事,于是就会有资源泄漏的问题,在线程频繁启动的软件中(比如某些服务器软件),迟早会让系统的内存资源耗尽!
_beginthreadex(内部也调用CreateThread)和_endthreadex就对这个内存块做了处理,所以没有问题!(不会有人故意用CreateThread创建然后用_endthreadex终止吧,而且线程的终止最好不要显式的调用终止函数,自然退出最好!)
线程的终止
《windows核心编程》:若要终止线程的运行,可以使用下面的方法:
1.线程函数返回(最好使用这种方法)。
2.通过调用ExitThread函数,线程将自行撤消(最好不要使用这种方法)。
3.同一个进程或另一个进程中的线程调用TerminateThread函数(应该避免使用这种方法)。
4.包含线程的进程终止运行(应该避免使用这种方法)。
下面是MSDN对这几种终止线程运行方法的说明:
1)BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
http://msdn.microsoft.com/en-us/library/ms686717(v=VS.85).aspx
2)VOID ExitThread(DWORD dwExitCode);
http://msdn.microsoft.com/en-us/library/ms682659(v=VS.85).aspx
3)void _endthread(void);
void _endthreadex(unsigned retval);
http://msdn.microsoft.com/en-us/library/hw264s73(VS.80).aspx
4)Terminating a Thread
http://msdn.microsoft.com/en-us/library/ms686724(v=VS.85).aspx