等待线程结束的更好方法是调用API WaitForSigleObject和WaitForMultipleObjects。前者用于等待一个线程由未激发状态变为激发状态,后者用于等待多个线程中全部或多个中的一个由未激发状态变为激发状态。对线程内核对象而言,如果线程在运行,则是未激发状态;如果线程已经退出,则是激发状态。不同内核对象的激发、未激发状态含义有所不同。
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle, //等待的内核对象句柄
__in DWORD dwMilliseconds //等待的超时时间
);
函数失败,返回WAIT_FAILED;
等待对象变为激发状态,返回WAIT_OBJECT_O;
等待超时,返回WAIT_TIMEOUT;
一个拥有mutex的线程结束前,没有释放掉mutex,则返回WAIT_ABANDONED.
DWORD WINAPI WaitForMultipleObjects(
__in DWORD nCount, //等待内核对象个数
__in const HANDLE* lpHandles,//内核对象数组
__in BOOL bWaitAll, //是否等待所有内核对象,还是等待其中一个变为激发状态就返回
__in DWORD dwMilliseconds //等待的超时时间
);
函数失败,返回WAIT_FAILED;
等待超时,返回WAIT_TIMEOUT;
bWaitAll为TRUE,所有对象变为激发状态,返回WAIT_OBJECT_O;
bWaitAll为FALSE,返回值减去WAIT_OBJECT_O的值就是变为激发状态内核对象在数组中的索引;
如果内核对象中有mutex,返回值可能在WAIT_ABANDONED到WAIT_ABANDONED+nCount-1。
下面是个<<WIN32多线程程序设计>>中用WaitForMultipleObjects实现的简单的线程池的例子,3个线程来完成6个任务。
/*
* MTVERYFY.h
*/
#pragma comment( lib, "USER32" )
#include <crtdbg.h>
#define MTASSERT(a) _ASSERTE(a)
#define MTVERIFY(a) if (!(a)) PrintError(#a,__FILE__,__LINE__,GetLastError())
__inline void PrintError(LPSTR linedesc, LPSTR filename, int lineno, DWORD errnum)
{
LPSTR lpBuffer;
char errbuf[256];
#ifdef _WINDOWS
char modulename[MAX_PATH];
#else // _WINDOWS
DWORD numread;
#endif // _WINDOWS
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errnum,
LANG_NEUTRAL,
(LPTSTR)&lpBuffer,
0,
NULL );
wsprintf(errbuf, "\nThe following call failed at line %d in %s:\n\n"
" %s\n\nReason: %s\n", lineno, filename, linedesc, lpBuffer);
#ifndef _WINDOWS
WriteFile(GetStdHandle(STD_ERROR_HANDLE), errbuf, strlen(errbuf), &numread, FALSE );
Sleep(3000);
#else
GetModuleFileName(NULL, modulename, MAX_PATH);
MessageBox(NULL, errbuf, modulename, MB_ICONWARNING|MB_OK|MB_TASKMODAL|MB_SETFOREGROUND);
#endif
exit(EXIT_FAILURE);
}
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include "MTVERIFY.h"
#define THREAD_POOL_SIZE 3
#define NUM_TASKS 6
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
HANDLE hThreads[THREAD_POOL_SIZE];
int i;
int slot = 0;
DWORD dwThreadId;
DWORD rc;
for ( i=0; i<NUM_TASKS; i++ )
{
if ( i >= THREAD_POOL_SIZE )
{
rc = WaitForMultipleObjects(THREAD_POOL_SIZE, hThreads, FALSE, INFINITE);
slot = rc - WAIT_OBJECT_0;
MTVERIFY( 0<=slot && slot<THREAD_POOL_SIZE );
printf("Slot %d terminated.\n",slot);
MTVERIFY( CloseHandle(hThreads[slot]) );
}
MTVERIFY( hThreads[slot++] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)slot, 0, &dwThreadId) );
printf("Launched thread #%d (slot %d).\n", i, slot);
}
rc = WaitForMultipleObjects(THREAD_POOL_SIZE, hThreads, TRUE, INFINITE);
MTVERIFY( WAIT_OBJECT_0<=rc && rc<WAIT_OBJECT_0+THREAD_POOL_SIZE );
for ( slot=0; slot<THREAD_POOL_SIZE; slot++ )
{
MTVERIFY( CloseHandle(hThreads[slot]) );
}
return EXIT_SUCCESS;
}
DWORD WINAPI ThreadFunc(LPVOID n)
{
srand( GetTickCount() );
Sleep( (rand()%10)*800+500 );
printf("Slot %d idle.\n", n);
return (DWORD)n;
}