第 46 章
xitThread
结束线程最直观的方法是调用Win32API 函数ExitThread,线程执行完线程函数的代码
后,会隐式调用ExitThread 函数,自动终止。当调用该函数时,当前线程的堆栈被释放,如
果当前线程是进程的最后一个线程,则进程也终止。它的函数原型如下。
VOID ExitThread(
DWORD dwExitCode
);
函数中主要参数的意义如下。
? dwExitCode:线程的返回码。
2.Win32API 函数TerminateThread
TerminateThread 用于强行终止一个线程。如果调用成功,返回TRUE,否则返回FALSE。
它的函数原型如下:
BOOL TerminateThread(
HANDLE hThread,
DWORD dwExitCode
);
函数中主要参数的意义如下。
? hThread:要终止的线程句柄。
? dwExitCode:线程的终止码,可以调用函数GetExitCodeThread 来得到。
函数GetExitCodeThread 用于得到线程的退出码,如果调用成功,返回TRUE,否则返回
FALSE。它的函数原型如下:
BOOL GetExitCodeThread(
HANDLE hThread,
LPDWORD lpExitCode
);
函数中主要参数的意义如下。
? hThread:要终止的线程句柄。
? LpExitCode:存放线程终止状态的变量指针。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·212·
3.C 运行库函数
C 运行库函数包括_endthread 和_endthreadex,分别用来结束一个由_beginthread 或
_beginthreadex 创建的线程。函数原型如下。需要注意的是,与ExitThread 相同,_endthreadex
并不关闭线程的句柄,因此,当调用这个函数之前,必须首先调用Win32 API 函数
CloseHandle。
void _endthread( void );
void _endthreadex(
unsigned retval
);
函数中主要参数的意义如下。
? retval:线程返回码。
4.函数AfxEndThread
函数AfxEndThread 用来终止由AfxBeginThread 创建的线程,它没有返回值,函数原型
如下:
void AFXAPI AfxEndThread(
UINT nExitCode,
BOOL bDelete = TRUE
);
函数中主要参数的意义如下。
? nExitCode:线程的返回码。
? bDelete:从内存中删除线程对象的标志。
9.3.3 线程的管理和cāo作
1.线程的挂起、继续和休眠
(1)挂起
如果一个正在执行的线程用完了自己的时间片,则这个线程将会被挂起,并将CPU 时间
分给其他等待的线程。也可以通过调用Win32 API 函数SuspendThread 来挂起一个正在执行
的线程,如果调用成功,返回线程上一次的挂起计数,否则返回-1。SuspendThread 的函数原
型如下:
DWORD SuspendThread(
HANDLE hThread
);
函数中主要参数的意义如下。
? hThread:线程的句柄。
MFC 将线程cāo作进行了封装,CWinThread 的对象可以调用它的成员函数SuspendThread
来挂起一个正在执行的线程。
枫叶文学网www.fywxw.com
第9 章 多线程
·213·
(2)继续
如果继续执行SuspendThread 挂起的线程,或者在执行时采用CREATE_SUSPENDED 标
记创建的线程,可以调用函数RescomThread,将当前被挂起的线程的挂起计数减一。如果一
个线程的挂起计数减为0,则线程开始继续执行。如果调用成功,返回线程上一次的挂起计
数,否则返回0xFFFFFFFF。如果返回值为0,则说明当前线程并没有挂起。如果返回1,说
明线程被挂起,现在开始继续执行。RescomThread 的函数原型如下:
DWORD RescomThread( );
(3)休眠
函数Sleep 可以让当前执行的线程休眠一段时间,而函数SleepEx 将线程挂起,等待下
列事件之一发生。
? 一个I/O 回调函数被调用。
? 线程需要调用一个异步的过程。
? 时间间隔到。
它们的函数原型如下:
VOID Sleep(
DWORD dwMilliseconds
);
函数中主要参数的意义如下。
? dwMilliseconds:休眠时间。
DWORD SleepEx(
DWORD dwMilliseconds,
BOOL bAlertable
);
函数中主要参数的意义如下。
? dwMilliseconds:超时间隔。
? bAlertable:指定函数是否依赖I/O 回调函数结束。
如果指定的时间间隔期满,则返回0。如果函数返回依赖于一个或多个I/O 回调函数则
返回WAIT_IO_COMPLETION,这种情况只有bAlertable 为TRUE 的时候才会发生。
2.线程的优先级
(1)级别
Windows 允许用户在线程执行的过程中动态地得到或者改变线程的优先级,使重要的线
程可以优先执行,占有较多的时间片。该过程可以通过调用Win32 API 函数SetThreadPriority
来调整进程内的线程优先级,Win32 进程的优先级如表9-2 所示,线程的优先级如表9-3 所
示。
表9-2 进程优先级列表
优先级 优先级值
ABOVE_NORMAL_PRIORITY_CLASS
大于NORMAL_PRIORITY_CLASS,
小于HIGH_PRIORITY_CLASS
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·214·
续表
优先级 优先级值
BELOW_NORMAL_PRIORITY_CLASS
大于IDLE_PRIORITY_CLASS,
小于NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS 13
IDLE_PRIORITY_CLASS 4
NORMAL_PRIORITY_CLASS 9(前台)或7(后台)
REALTIME_PRIORITY_CLASS 24
表9-3 线程优先级列表
优先级 级别
THREAD_PRIORITY_ABOVE_NORMAL 比进程优先级高一级
THREAD_PRIORITY_BELOW_NORMAL 比进程优先级低一级
THREAD_PRIORITY_HIGHEST 比进程优先级高两级
THREAD_PRIORITY_LOWEST 比进程优先级低两级
THREAD_PRIORITY_NORMAL 与进程优先级相同
THREAD_PRIORITY_TIME_CRITICAL 把线程优先级设为15
THREAD_PRIORITY_IDLE 把线程优先级设为1
(2)优先级的设置和获取
可以通过调用Win32 API 函数GetThreadPriority 或SetThreadPriority 实现或修改线程优先级
的功能,如果调用成功,返回线程的优先级,否则返回THREAD_PRIORITY_ERROR_RETURN。
GetThreadPriority 的函数原型如下:
int GetThreadPriority(
HANDLE hThread
);
函数中主要参数的意义如下。
? hThread:线程的局柄。
函数SetThreadPriority 用来设定线程的优先级,如果调用成功,返回非0,否则返回0。
它的函数原型如下:
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);
函数中主要参数的意义如下。
? hThread:线程的局柄;
? nPriority:要设定的优先级。
在本节最后给出的示例中,读者可以看到如何利用SetThreadPriority 设定一个线程的优
先级。
3.线程ID 的判断
在创建线程的同时,系统会为每个线程生成一个线程ID。任何两个线程ID 都不会相同。
许多Win32 API 函数都以线程ID 作为参数对线程进行cāo作。在调用CreateThread 或者
_begintread 创建线程的时候,会返回线程ID,可以在这个时候将ID 保存下来。调用Win32 API
枫叶文学网www.fywxw.com
第9 章 多线程
·215·
函数GetCurrentThreadID 可以得到当前线程ID。该函数没有参数,它的函数原型如下:
DWORD GetCurrentThreadId(VOID);
用户也可以调用Win32 API 函数GetCurrentThread 得到当前线程的伪句柄,函数原型如
下:
HANDLE GetCurrentThread(VOID);
4.线程的切换
如果希望cāo作系统从当前正在执行的线程切换到其他就绪线程,可以通过调用Win32
API 函数SwitchToThread 实现,切换后的线程由cāo作系统选择。SwitchToThread 函数没有参
数,它的函数原型如下:
BOOL SwitchToThread(VOID);
5.打开线程
Win32 API 函数OpenThread 可以打开一个存在的线程对象。如果调用成功,返回指定线
程的句柄,否则返回NULL。它的函数原型如下:
HANDLE OpenThread(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwThreadId
);
函数中主要参数的意义如下。
? dwDesiredAccess:描述希望对线程进行的访问。
? bInheritHandle:指定返回的句柄是否可以被一个当前进程创建的新进程继承。
? dwThreadId:被访问线程的ID。
6.线程函数ThreadProc
线程函数是一个由用户定义的函数,作为执行线程的入口。在调用创建线程函数的时候,
将ThreadProc 作为参数传入。返回调用成功或失败的标记。它的函数原型如下:
DWORD WINAPI ThreadProc(
LPVOID lpParcomter
);
函数中主要参数的意义如下。
? lpParcomter:传给线程函数的参数。
7.获得线程的时间信息
线程的生命周期中,可以调用GetThreadTcoms 函数得到指定线程的时间信息。如果调用
成功,返回非0 值,否则返回0。GetThreadTcoms 函数原型如下:
BOOL GetThreadTcoms(
HANDLE hThread,
LPFILETIME lpCreationTcom,
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·216·
LPFILETIME lpExitTcom,
LPFILETIME lpKernelTcom,
LPFILETIME lpUserTcom
);
函数中主要参数的意义如下。
? hThread:线程的句柄。
? lpCreationTcom:保存线程的创建时间。
? lpExitTcom:保存线程的生存时间。
? lpKernelTcom:保存线程在内核模式下的生存时间。
? lpUserTcom:保存线程在用户模式下的执行时间。
FILETIME是一个64 位数的结构,表示从1601 年1 月1 日到现在以十亿分之一为间隔
的时间片数。它的定义如下:
typedef struct _FILETIME {
DWORD dwLowDateTcom;
DWORD dwHighDateTcom;
} FILETIME, *PFILETIME;
结构中主要成员变量的意义。
? dwLowDateTcom:表示低32 位字节。
? dwHighDateTcom:表示高32 位字节。
8.处理器相关cāo作
(1)SetThreadAffinityMask 函数
该函数用于为指定的线程设置其处理器相似xìng掩码。一个线程相似xìng掩码是一个位向
量,每一位表示一个线程可以使用的处理器。线程相似xìng只对多处理器计算机有作用。对通
常使用的单CPU 机器无效。如果调用成功,返回非0 值。否则返回0。
SetThreadAffinityMask 函数原型入下:
DWORD_PTR SetThreadAffinityMask (
HANDLE hThread,
DWORD_PTR dwThreadAffinityMask
);
松语文学免费小说阅读_www.16sy.com
结束线程最直观的方法是调用Win32API 函数ExitThread,线程执行完线程函数的代码
后,会隐式调用ExitThread 函数,自动终止。当调用该函数时,当前线程的堆栈被释放,如
果当前线程是进程的最后一个线程,则进程也终止。它的函数原型如下。
VOID ExitThread(
DWORD dwExitCode
);
函数中主要参数的意义如下。
? dwExitCode:线程的返回码。
2.Win32API 函数TerminateThread
TerminateThread 用于强行终止一个线程。如果调用成功,返回TRUE,否则返回FALSE。
它的函数原型如下:
BOOL TerminateThread(
HANDLE hThread,
DWORD dwExitCode
);
函数中主要参数的意义如下。
? hThread:要终止的线程句柄。
? dwExitCode:线程的终止码,可以调用函数GetExitCodeThread 来得到。
函数GetExitCodeThread 用于得到线程的退出码,如果调用成功,返回TRUE,否则返回
FALSE。它的函数原型如下:
BOOL GetExitCodeThread(
HANDLE hThread,
LPDWORD lpExitCode
);
函数中主要参数的意义如下。
? hThread:要终止的线程句柄。
? LpExitCode:存放线程终止状态的变量指针。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·212·
3.C 运行库函数
C 运行库函数包括_endthread 和_endthreadex,分别用来结束一个由_beginthread 或
_beginthreadex 创建的线程。函数原型如下。需要注意的是,与ExitThread 相同,_endthreadex
并不关闭线程的句柄,因此,当调用这个函数之前,必须首先调用Win32 API 函数
CloseHandle。
void _endthread( void );
void _endthreadex(
unsigned retval
);
函数中主要参数的意义如下。
? retval:线程返回码。
4.函数AfxEndThread
函数AfxEndThread 用来终止由AfxBeginThread 创建的线程,它没有返回值,函数原型
如下:
void AFXAPI AfxEndThread(
UINT nExitCode,
BOOL bDelete = TRUE
);
函数中主要参数的意义如下。
? nExitCode:线程的返回码。
? bDelete:从内存中删除线程对象的标志。
9.3.3 线程的管理和cāo作
1.线程的挂起、继续和休眠
(1)挂起
如果一个正在执行的线程用完了自己的时间片,则这个线程将会被挂起,并将CPU 时间
分给其他等待的线程。也可以通过调用Win32 API 函数SuspendThread 来挂起一个正在执行
的线程,如果调用成功,返回线程上一次的挂起计数,否则返回-1。SuspendThread 的函数原
型如下:
DWORD SuspendThread(
HANDLE hThread
);
函数中主要参数的意义如下。
? hThread:线程的句柄。
MFC 将线程cāo作进行了封装,CWinThread 的对象可以调用它的成员函数SuspendThread
来挂起一个正在执行的线程。
枫叶文学网www.fywxw.com
第9 章 多线程
·213·
(2)继续
如果继续执行SuspendThread 挂起的线程,或者在执行时采用CREATE_SUSPENDED 标
记创建的线程,可以调用函数RescomThread,将当前被挂起的线程的挂起计数减一。如果一
个线程的挂起计数减为0,则线程开始继续执行。如果调用成功,返回线程上一次的挂起计
数,否则返回0xFFFFFFFF。如果返回值为0,则说明当前线程并没有挂起。如果返回1,说
明线程被挂起,现在开始继续执行。RescomThread 的函数原型如下:
DWORD RescomThread( );
(3)休眠
函数Sleep 可以让当前执行的线程休眠一段时间,而函数SleepEx 将线程挂起,等待下
列事件之一发生。
? 一个I/O 回调函数被调用。
? 线程需要调用一个异步的过程。
? 时间间隔到。
它们的函数原型如下:
VOID Sleep(
DWORD dwMilliseconds
);
函数中主要参数的意义如下。
? dwMilliseconds:休眠时间。
DWORD SleepEx(
DWORD dwMilliseconds,
BOOL bAlertable
);
函数中主要参数的意义如下。
? dwMilliseconds:超时间隔。
? bAlertable:指定函数是否依赖I/O 回调函数结束。
如果指定的时间间隔期满,则返回0。如果函数返回依赖于一个或多个I/O 回调函数则
返回WAIT_IO_COMPLETION,这种情况只有bAlertable 为TRUE 的时候才会发生。
2.线程的优先级
(1)级别
Windows 允许用户在线程执行的过程中动态地得到或者改变线程的优先级,使重要的线
程可以优先执行,占有较多的时间片。该过程可以通过调用Win32 API 函数SetThreadPriority
来调整进程内的线程优先级,Win32 进程的优先级如表9-2 所示,线程的优先级如表9-3 所
示。
表9-2 进程优先级列表
优先级 优先级值
ABOVE_NORMAL_PRIORITY_CLASS
大于NORMAL_PRIORITY_CLASS,
小于HIGH_PRIORITY_CLASS
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·214·
续表
优先级 优先级值
BELOW_NORMAL_PRIORITY_CLASS
大于IDLE_PRIORITY_CLASS,
小于NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS 13
IDLE_PRIORITY_CLASS 4
NORMAL_PRIORITY_CLASS 9(前台)或7(后台)
REALTIME_PRIORITY_CLASS 24
表9-3 线程优先级列表
优先级 级别
THREAD_PRIORITY_ABOVE_NORMAL 比进程优先级高一级
THREAD_PRIORITY_BELOW_NORMAL 比进程优先级低一级
THREAD_PRIORITY_HIGHEST 比进程优先级高两级
THREAD_PRIORITY_LOWEST 比进程优先级低两级
THREAD_PRIORITY_NORMAL 与进程优先级相同
THREAD_PRIORITY_TIME_CRITICAL 把线程优先级设为15
THREAD_PRIORITY_IDLE 把线程优先级设为1
(2)优先级的设置和获取
可以通过调用Win32 API 函数GetThreadPriority 或SetThreadPriority 实现或修改线程优先级
的功能,如果调用成功,返回线程的优先级,否则返回THREAD_PRIORITY_ERROR_RETURN。
GetThreadPriority 的函数原型如下:
int GetThreadPriority(
HANDLE hThread
);
函数中主要参数的意义如下。
? hThread:线程的局柄。
函数SetThreadPriority 用来设定线程的优先级,如果调用成功,返回非0,否则返回0。
它的函数原型如下:
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority
);
函数中主要参数的意义如下。
? hThread:线程的局柄;
? nPriority:要设定的优先级。
在本节最后给出的示例中,读者可以看到如何利用SetThreadPriority 设定一个线程的优
先级。
3.线程ID 的判断
在创建线程的同时,系统会为每个线程生成一个线程ID。任何两个线程ID 都不会相同。
许多Win32 API 函数都以线程ID 作为参数对线程进行cāo作。在调用CreateThread 或者
_begintread 创建线程的时候,会返回线程ID,可以在这个时候将ID 保存下来。调用Win32 API
枫叶文学网www.fywxw.com
第9 章 多线程
·215·
函数GetCurrentThreadID 可以得到当前线程ID。该函数没有参数,它的函数原型如下:
DWORD GetCurrentThreadId(VOID);
用户也可以调用Win32 API 函数GetCurrentThread 得到当前线程的伪句柄,函数原型如
下:
HANDLE GetCurrentThread(VOID);
4.线程的切换
如果希望cāo作系统从当前正在执行的线程切换到其他就绪线程,可以通过调用Win32
API 函数SwitchToThread 实现,切换后的线程由cāo作系统选择。SwitchToThread 函数没有参
数,它的函数原型如下:
BOOL SwitchToThread(VOID);
5.打开线程
Win32 API 函数OpenThread 可以打开一个存在的线程对象。如果调用成功,返回指定线
程的句柄,否则返回NULL。它的函数原型如下:
HANDLE OpenThread(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwThreadId
);
函数中主要参数的意义如下。
? dwDesiredAccess:描述希望对线程进行的访问。
? bInheritHandle:指定返回的句柄是否可以被一个当前进程创建的新进程继承。
? dwThreadId:被访问线程的ID。
6.线程函数ThreadProc
线程函数是一个由用户定义的函数,作为执行线程的入口。在调用创建线程函数的时候,
将ThreadProc 作为参数传入。返回调用成功或失败的标记。它的函数原型如下:
DWORD WINAPI ThreadProc(
LPVOID lpParcomter
);
函数中主要参数的意义如下。
? lpParcomter:传给线程函数的参数。
7.获得线程的时间信息
线程的生命周期中,可以调用GetThreadTcoms 函数得到指定线程的时间信息。如果调用
成功,返回非0 值,否则返回0。GetThreadTcoms 函数原型如下:
BOOL GetThreadTcoms(
HANDLE hThread,
LPFILETIME lpCreationTcom,
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·216·
LPFILETIME lpExitTcom,
LPFILETIME lpKernelTcom,
LPFILETIME lpUserTcom
);
函数中主要参数的意义如下。
? hThread:线程的句柄。
? lpCreationTcom:保存线程的创建时间。
? lpExitTcom:保存线程的生存时间。
? lpKernelTcom:保存线程在内核模式下的生存时间。
? lpUserTcom:保存线程在用户模式下的执行时间。
FILETIME是一个64 位数的结构,表示从1601 年1 月1 日到现在以十亿分之一为间隔
的时间片数。它的定义如下:
typedef struct _FILETIME {
DWORD dwLowDateTcom;
DWORD dwHighDateTcom;
} FILETIME, *PFILETIME;
结构中主要成员变量的意义。
? dwLowDateTcom:表示低32 位字节。
? dwHighDateTcom:表示高32 位字节。
8.处理器相关cāo作
(1)SetThreadAffinityMask 函数
该函数用于为指定的线程设置其处理器相似xìng掩码。一个线程相似xìng掩码是一个位向
量,每一位表示一个线程可以使用的处理器。线程相似xìng只对多处理器计算机有作用。对通
常使用的单CPU 机器无效。如果调用成功,返回非0 值。否则返回0。
SetThreadAffinityMask 函数原型入下:
DWORD_PTR SetThreadAffinityMask (
HANDLE hThread,
DWORD_PTR dwThreadAffinityMask
);
松语文学免费小说阅读_www.16sy.com