Windows 核心编程之6 线程内核对象

线程内核对象
每个进程里,都有一个线程,操作系统用线程内核对象来管理线程。

线程有2部分组成:1 线程内核对象。 操作系统来管理线程   2 线程栈, 来存在函数和局部变量的地址空间。


什么情况下使用多线程?
     当各个任务彼此独立时,可以使用多线程,如:开一个后台线程来检测语法。
什么情况下不要使用多线程?
      任务联系紧密。如 扫描一个目录的文件,就不适合开多个线程处理,这样处理起来复杂度很高!

实现CreateThread 来创建一个线程.
如果是C、C++代码的话,使用_beginThreadEx来创建线程
为什么? 因为有些C函数里面使用了静态变量,那么多个线程执行的话,会有冲突,但是_beginThreadex做了线程局部处理,它内部就调用了CreateThread函数。



WINBASEAPI   表示是winbase.h的API
__out_opt       表示是输出
HANDLE
WINAPI
CreateThread(
    __in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,   安全属性,一般为NULL表示默认
    __in      SIZE_T dwStackSize,    线程栈的空间,一般使用0来表示默认值
    __in      LPTHREAD_START_ROUTINE lpStartAddress,  线程函数地址
    __in_opt  LPVOID lpParameter, 线程函数参数
    __in      DWORD dwCreationFlags,  创建线程时,指定啥标志 0 表示立即开始执行,CREATE_SUSPENDED 表示暂停
    __out_opt LPDWORD lpThreadId   返回线程ID,不需要时,可以传递NULL,表示不关心
    );


终止运行线程的4种方式:

1 线程函数返回( 推荐

可以清理C++对象资源,会调用C++的析构函数
清理线程栈

2 自己调用ExitThread( 避免使用

不会调用C++的析构函数
清理线程栈
如果使用的是C++代码,那么调用_endThreadEx() 来替换ExitThread

3 其它线程调用TerminateThread()   避免使用

不会调用C++析构函数,也不会清理线程栈
ExitThread来结束的线程,会清理堆栈,但是调用terminateThread()函数 不会清理堆栈信息,除非线程所在进程终止。


4 线程所在的进程终止                       避免使用
C++析构函数不会调用,线程被强行杀死,正常的清理工作没有执行。



线程终止时,会发生以下事情:

1  线程拥有的所有对象句柄被释放
一个线程有2个用户对象: 窗口和挂钩

2 退出码有STILL_ACTIVE 变成 ExitThread 或者TerminateThread 返回的退出码

3 线程内核对象变成触发状态

4 如果线程是最后一个活动线程,那么进程也终止。

5 线程内核对象的引用计数减一


C和C++库
标准的C和C++库,最开始不是为了多线程设计的,在多线程环境下有些函数会出问题:
errno,_doserrno, strtok, _wcstok, strerror, _strerror, tmpnam, tmpfile,asctime,gmtime,等

所以要不要调用系统的CreateThread,而要调用C,C++运行库 _beginthreadex

_beginthreadex 分配和初始化 初始化数据块,并将它与新的线程关联起来
_endthreadex  函数 在线程终止运行的 释放分配的数据块

不要使用C和C++运行库的这一对函数
_beginthread , _endthread

了解自己的身份

返回当前进程的句柄  和  ID
HANDLE GetCurrentProcess();
DWORD GetCurentProceddID();

返回当前线程的句柄   和 ID
HANDLE GetCurrentThread();
DWORD  GetCureentThreadID();


注意: 上面这2个函数返回的都是 伪句柄

伪句柄:表示当前线程的句柄,即调用线程的句柄。下面举一个示例来分析
#include <iostream>
#include <vector>
#include <map>
#include <Windows.h>

#include <tchar.h>
#include <process.h>
#include <Strsafe.h>

HANDLE ghthreadCurrent = NULL;
unsigned int WINAPI ThreadFunc2(LPVOID lp);

unsigned int WINAPI ThreadFunc1(LPVOID lp)
{
	HANDLE hThread = GetCurrentThread();

	ghthreadCurrent =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc2, hThread, 0, NULL);

	while(1)
	{
		printf("111\n");
		Sleep(1000);
	}
	return 0;
}

unsigned int WINAPI ThreadFunc2(LPVOID lp)
{
	HANDLE hThread = (HANDLE)lp;

	TerminateThread(hThread,0);

	return 0;
}

int main()
{
	HANDLE hThread1 =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc1, NULL, 0, NULL );

	WaitForSingleObject(hThread1,INFINITE);

	return 0;
}



线程2 的线程函数 TerminateThread 会把自己杀死,不会杀死线程1


使用一个复制句柄的函数 DuplicateHandle() 来复制句柄
#include <iostream>
#include <vector>
#include <map>
#include <Windows.h>

#include <tchar.h>
#include <process.h>
#include <Strsafe.h>

unsigned int WINAPI ThreadFunc2(LPVOID lp);

unsigned int WINAPI ThreadFunc1(LPVOID lp)
{
	HANDLE hThread = GetCurrentThread();
	HANDLE hTagrealThread = NULL;

	BOOL bOk = DuplicateHandle(GetCurrentProcess(),hThread,GetCurrentProcess(),
		&hTagrealThread,0,FALSE,DUPLICATE_SAME_ACCESS);

	(HANDLE) _beginthreadex(NULL, 0, ThreadFunc2, hTagrealThread, 0, NULL);

	while(1)
	{
		printf("111\n");
		Sleep(1000);
	}
	return 0;
}

unsigned int WINAPI ThreadFunc2(LPVOID lp)
{
	HANDLE hThread = (HANDLE)lp;

	Sleep(5000);

	TerminateThread(hThread,0);

	//必须要关闭句柄
	CloseHandle(hThread);

	return 0;
}

int main()
{
	HANDLE hThread1 =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc1, NULL, 0, NULL );

	WaitForSingleObject(hThread1,INFINITE);

	CloseHandle(hThread1);

	printf("main exit\n");

	system("pause");

	return 0;
}

线程2函数,杀死的是线程1
 最后要关闭线程1的线程内核对象
复制一个句柄后,线程内核对象引用计数会加1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值