进程是4GB,线程是EIP
一、线程控制
1.1 创建线程
// 返回值:线程句柄
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性 通常为NULL
SIZE_T dwStackSize, // 参数用于设定线程可以将多少地址空间用于它自己的堆栈
// 每个线程拥有它自己的堆栈
LPTHREAD_START_ROUTINE lpStartAddress, // 参数用于指明想要新线程执行的线程函数的地址
LPVOID lpParameter, // 线程函数的参数
// 在线程启动执行时将该参数传递给线程函数
// 既可以是数字,也可以是指向包含其他信息的一个数据结构的指针
DWORD dwCreationFlags, // 0 创建完毕立即调度 CREATE_SUSPENDED创建后挂起
LPDWORD lpThreadId // 线程ID
);
1.1.1 线程句柄与线程ID
线程是由Windows内核负责创建与管理的,句柄相当于一个令牌,有了这个令牌就可以使用线程对象.
线程ID是身份证,唯一的,系统进行线程调度的时候要使用的.
1.1.2 创建线程
//创建一个新的线程
HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
//如果不在其他的地方引用它 关闭句柄
::CloseHandle(hThread);
1.1.3 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
return 结束码;
}
1.2 挂起线程
::SuspendThread(hThread);
1.3 恢复线程
::ResumeThread(hThread);
1.4 终止线程
1.4.1 退出码
退出码,用于表示程序的执行状态,线程函数执行结束时返回的值。
1.4.2 方式一: ::ExitThread(dwExitCode)
说明:用于结束进程,在线程函数中同步调用
,退出码为传入的dwExitCode
参数的值。
特点:
- 会把当前线程的整个堆栈释放(从线程开始跑分配的堆栈),但是一但使用此函数,由于整个堆栈被释放,你就没有机会做任何的东西了。
- 而且在释放堆栈时不会管线程函数的堆中使用的空间,也就是或
new
的对象不会释放,需要手动delete
1.4.3 方式二:线程函数返回
说明:线程函数正常执行,执行完毕时通过return返回退出码
,线程结束。
特点:
- 在
return
前可以编写代码delete
在线程函数中所new
的对象,用法灵活。
1.4.4 方式三: ::TerminateThread(hThread, dwExitCode)
说明:用于结束进程,在线程函数外
使用,异步调用
特点:
-
在终止线程的同时会接着向下执行。不会清理指定线程的堆栈。
-
需要通过
::WaitForSingleObject(hThread,INFINITE);
函数等待异步调用的结束,否则会在进程未结束时就向下执行。
1.5 判断线程是否结束
BOOL GetExitCodeThread(
HADLE hThread,
LPDWORD lpExitCode;
);
返回BOOL值,用于判断线程是否结束,传入线程句柄
和退出码指针
,如果线程结束,函数会将退出码存储到传入退出码指针
所指向的地址。
二、内核对象
2.1 什么是内核对象?
内核对象:进程、线程、文件、文件映射、事件、互斥体等等
2.2 内核对象的通知状态
内核对象中的每种对象都可以说是处于已通知或未通知的状态之中
这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的,在内核中就是个BOOL值
- 已通知 TRUE
- 未通知 FALSE
当线程正在运行的时候,线程内核对象处于未通知状态;
当线程终止运行的时候,线程内核对象变为已通知状态每种内核对象的通知状态对应不同的含义,会产生不同的结果(例如
WaitForSingleObject()
后回归未通知状态):重点 对于进程和线程,内核通知状态代表进程或线程是否正在执行,调用
WaitForSingleObject()
等待后,不会回归未通知状态。
2.3 内核对象的使用
2.3.1 事件内核的创建
// 创建事件内核
HANDLE g_hEvent = CreateEvent(NULL, TRUE, FALSE, "XYZ");
// 创建互斥体内核
HANDLE g_hMutex = CreateMutex(NULL, FLASE, "XYZ");
2.3.2 事件内核的获取
// 获取事件内核
HANDLE g_hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, "XYZ");
// 获取互斥体内核
HANDLE g_hMutex = OpenMutex(EVENT_ALL_ACCESS, FALSE, "XYZ");
2.4 内核对象的销毁
2.4.1 事件内核的销毁
关闭事件内核的句柄
CloseHandle(g_hEvent);
- 当没有其他程序引用时,系统会销毁内核对象(使用数量)。
- 内核对象的生命周期,可能比创建它的对象要长。
4.2.2 内核的生命周期(计数器)
每个内核对象都有一个计数器
,记录着内核对象的使用情况。当内核对象中的计数器
的值为 0 时,系统会销毁
内核对象。
拿事件(Event)来举例:
- 调用
CreateEvent()
或OpenEvent()
时,计数器+1
- 调用
CloseHandle(hEvent)
时,对应事件的计数器-1
,当计数器回归0
时,系统会销毁内核对象
2.5 WaitForSingleObject()
函数
DWORD WaitForSingleObject(
HANDLE hHandle; //handle to object
DWORD dwMilliseconds