终止线程的运行
若要终止线程的运行,可以使用下面的方法:
• 线程函数返回(最好使用这种方法) 。
• 通过调用ExitThread函数,线程将自行撤消(最好不要使用这种方法) 。
• 同一个进程或另一个进程中的线程调用TerminateThread函数(应该避免使用这种方法) 。
• 包含线程的进程终止运行(应该避免使用这种方法) 。
- 线程函数返回
始终都应该将线程设计成这样的形式,即当想要线程终止运行时,它们就能够返回。这是确保所有线程资源被正确地清除的唯一办法。
如果线程能够返回,就可以确保下列事项的实现:
• 在线程函数中创建的所有C + +对象均将通过它们的撤消函数正确地撤消。
• 操作系统将正确地释放线程堆栈使用的内存。
• 系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
• 系统将递减线程内核对象的使用计数。
- ExitThread函数
可以让线程调用ExitThread函数,以便强制线程终止运行:
VOID ExitThread(DWORD dwExitCode);
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++类对象)将不被撤消。
ExitThread函数是Windows用来撤消线程的函数。如果编写C/C++代码,应该使用编译环境的运行期函数(Visual C++的_ endthreadex)。
- TerminateThread函数
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);
hThread参数用于标识被终止运行的线程的句柄。当线程终止运行时,它的退出代码成为你作为dwExitCode参数传递的值。同时,线程的内核对象的使用计数也被递减。
ExitThread总是撤消调用的线程,而TerminateThread能够撤消任何线程。TerminateThread是异步运行的函数,当函数返回时,不能保证线程被撤消。当使用返回或调用ExitThread的方法撤消线程时,该线程的内存堆栈也被撤消。但 TerminateThread在线程的进程终止运行之前,系统不撤消该线程的堆栈。
设计良好的应用程序从来不使用这个函数, 因为被终止运行的线程收不到它被撤消的通知。线程不能正确地清除,并且不能防止自己被撤消。
- 在进程终止运行时撤消线程
由于整个进程已经被关闭,进程使用的所有资源肯定已被清除。这当然包括所有线程的堆栈。这两个函数会导致进程中的剩余线程被强制撤消,这意味着正确的应用程序清除没有发生。
- 线程终止运行时发生的操作
当线程终止运行时,会发生下列操作:
• 线程拥有的所有用户对象均被释放。在 Windows中,大多数对象是由包含创建这些对象的线程的进程拥有的。但是一个线程拥有两个用户对象,即窗口和挂钩。当线程终止运行时,系统会自动撤消任何窗口,并且卸载线程创建的或安装的任何挂钩。其他对象只有在拥有线程的进程终止运行时才被撤消。
• 线程的退出代码从S T I L L _ A C T I V E改为传递给ExitThread或TerminateThread的代码。
• 线程内核对象的状态变为已通知。
• 如果线程是进程中最后一个活动线程,系统也将进程视为已经终止运行。
• 线程内核对象的使用计数递减1。
当一个线程终止运行时,在与它相关联的线程内核对象的所有未结束的引用关闭之前,该
内核对象不会自动被释放。
一旦线程不再运行,系统中就没有别的线程能够处理该线程的句柄。然而别的线程可以调用GetExitCodeThread来检查由h T h r e a d标识的线程是否已经终止运行。
BOOL GetExitCodeThread(HANDLE hThread, PDWORD pdwExitCode);
退出代码的值在pdwExitCode指向的DWORD中返回。如果调用GetExitCodeThread时线程尚未终止运行,该函数就用STILL_ACTIVE标识符(定义为0 x 1 0 3)填入DWORD。如果该函数运行成功,便返回T R U E。