结束一个线程,听起来好容易,但是结束程序必须按次序进行,以避免发生race conditions。让程序依次序进行是非常重要的,特别是在程序要结束之前。结束一个程序就好像拆除一栋建筑物一样,在你以推土机轧平它之前,你必须确定每一个人都安全离开了屋子。结束一个程序也是这样,每一个线程都被迫结束,不管它进行到哪里。
利用 TerminateThread() 放弃一个线程
BOOL TerminateThread(
HANDLE hThread,
DWORD dwExitCode
);
参数
hThread 欲令其结束之线程的handle。该线程就是我们的行动目标。
dwExitCode 该线程的结束代码。
返回值
如果函数成功,则传回TRUE。如果失败,则传回FALSE。GetLastError() 可以获知更多细节。
TerminateThread() 强迫其行动目标(一个线程)结束,手段激烈而有力,甚至不允许该线程有任何“挣扎”的机会。这带来的副作用便是,线程没有机会在结束前清理自己。对线程而言,这可能导致前功尽弃。这个函数不会在目标线程中丢出一个异常情况(exception),目标线程在核心层面就被根本抹杀了。目标线程没有机会捕捉所谓的“结束请求”,并从而获得清理自己的机会。
还有另一个令人不愉快的情况。目标线程的堆栈没有被释放掉,于是可能会引起一大块内存泄漏(memory leak)。而且,任何一个与此线程有附着关系的DLLs 也都没有机会获得“线程解除附着”的通知。
此函数唯一可以预期并依恃的是,线程handle 将变成激发状态(译注:因为线程结束了),并且传回dw ExitCode 所指定的结束代码。
这个函数所带来的隐伏危机还包括:如果线程正进入一个critical section 之中,该critical section 将因此永远处于锁定状态,因为critical section 不像mutex 那样有所谓的" abandoned" 状态。如果目标线程正在更新一份数据结构,这份数据结构也将永远处于不稳定状态。没有任何方法可以阻止这些问题的发生。
我的结论是:离Term inateThread() 远远地!
设立一个标记
Win32 核准的做法是在你的程序代码中设立一个标记,利用其值来要求线程结束自己。
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include "MtVerify.h"
DWORD WINAPI ThreadFunc(LPVOID);
HANDLE hRequestExitEvent = FALSE;
int main()
{
HANDLE hThreads[2];
DWORD dwThreadId;
DWORD dwExitCode = 0;
int i;
hRequestExitEvent = CreateEvent(
NULL, TRUE, FALSE, NULL);
for (i=0; i<2; i++)
MTVERIFY( hThreads[i] = CreateThread(NULL,
0,
ThreadFunc,
(LPVOID)i,
0,
&dwThreadId )
);
// Wait around for awhile, make
// sure the thread is running.
Sleep(1000);
SetEvent(hRequestExitEvent);//发送结束所有线程通知
WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);//主线程等待所有线程结束
for (i=0; i<2; i++)
MTVERIFY( CloseHandle(hThreads[i]) );
return EXIT_SUCCESS;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
int i;
int inside = 0;
UNREFERENCED_PARAMETER(p);
/* Seed the random-number generator */
srand( (unsigned)time( NULL ) );
for (i=0; i<1000000; i++)
{
double x = (double)(rand())/RAND_MAX;
double y = (double)(rand())/RAND_MAX;
if ( (x*x + y*y) <= 1.0 )
inside++;
if (WaitForSingleObject(hRequestExitEvent, 0) != WAIT_TIMEOUT)//被通知结束
{
printf("Received request to terminate\n");
return (DWORD)-1;
}
}
printf("PI = %.4g\n", (double)inside / i * 4);
return 0;
}
文字版电子书-----请点击这里