一、进程由两部分组成,一个是进程内核对象,另一个是地址空间。同样线程也是由两部分组成的:一个是线程的内核对象,另一个是线程堆栈。
二、线程的进入点函数
每个线程必须拥有一个进入点函数,线程从这个进入点开始运行。主线程的进入点函数:即main、wmain、WinMain或wWinMain。辅助线程的进入点函数的原型:
DWORD WINAPI ThreadFunc(PVOID pvParam);
三、CreateThread函数原型
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD cbStack,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD fdwCreate,
PDWORD pdwThreadID);
注意:尽量使用CreateThread的替代函数。
1、 SECURITY_ATTRIBUTES结构:
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
内核对象能够得到安全描述符的保护。安全描述符用于描述谁创建了该对象,谁能够访问或使用该对象,谁无权访问该对象。
NULL:默认安全属性。
bInheritHandle = TRUE:子进程能够继承该线程对象的句柄。
2、 cbStack参数用于设定线程可以降多少地址空间用于它自己的堆栈。
可以使用链接程序的/STACK开关来控制这个值:/STACK:[reserve] [,commit]
3、 pfnStartAddr和pvParam
pfnStartAddr参数用于指明想要新线程执行的线程函数的地址。pvParam参数提供了一个初始化值传递给线程函数,可以是数字值也可以是一个数据结构的指针。
4、 fdwCreate参数可以设定用于控制创建线程的其他标志。只有两个值:0创建后立即调度;CREATE_SUSPENDED暂停该线程的运行。
5、 pdwThreadID用来存放系统分配给新线程的ID。必须是DWORD的一个有效地址。
四、终止线程的运行
l 线程函数返回(最好的方法)
l 调用ExitThread函数,线程将自行撤销(最好不用的方法)
l 同一个进程或另一个进程中的线程调用TerminateThread函数(避免使用的方法)
l 包含线程的进程终止运行(避免使用的方法)
线程函数返回:这是确保所有线程资源被正确释放的唯一办法。线程返回做的事项:
l 线程创建的所有C++对象通过他们的撤销函数正确的撤销
l 操作系统将正确地释放线程堆栈使用的内存
l 系统将线程的退出代码设置为线程函数的返回值
l 系统将递减线程内核对象的使用计数
ExitThread函数:VOID ExitThread(DWORD dwExitCode);
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源将不被撤销。
TerminateThread函数:BOOL TerminateThread(HANFDLE hThread, DWORD dwExitCode);
该函数是异步运行的函数。
五、C/C++运行期库的考虑
若要创建一个新线程,绝对不要调用操作系统的CreateThread函数,必须调用C/C++运行期库函数_beginthreadex:
unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned (*start_address)(void *),
void *arglist,
unsigned initflag,
unsigned *thrdaddr);
六、线程ID
返回调用线程的进程的伪句柄或线程内核对象的伪句柄:
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
返回调用线程的进程的唯一ID或它自己的唯一ID:
DWORD GetCurrentProcessId();
DWORD GetCurrentThreadId();
将伪句柄转换为实句柄:
BOOL DuplicateHandle(
HANDLE hSourceProcess,
HANDLE hSource,
HANDLE hTargetProcess,
PHANDLE phTarget,
DWORD fdwAccess,
BOOL bInheritHandle,
DWORD fdwOptions);
注意DuplicateHandle会递增特定对象的使用计数,一次完成对复制句柄的使用时,应该将目标句柄传递给CloseHandle,来递减对象的使用计数。