课前复习
内核对象
内核对象的特性:
- 全局性 - 可以跨进程使用
 引用计数 -
- 使用CreateXXX 或 OpenXXX 得到内核对象句柄时,引用计数会增加
 - 使用CloseHandle 递减引用计数
 - 引用计数等于0的时候, 才会被销毁
 
安全描述符
- 使用进程默认的安全描述符
 
句柄表
- 内核对象句柄值一般是句柄表的下标.
 - 每个进程都自身独立的句柄表.
 - 内核对象可以跨进程使用,但是句柄的值不能跨进程使用
 
进程
- 提供一个虚拟内存地址空间
 - 由主模块和其它模块组成
 - 进程必须有一个主线程
 
进程通讯
- WM_COPYDATA
 邮槽
- 创建邮槽对象: 
CreateMailslot, 邮槽名字特征是:\\.\mailslot\ - 打开邮槽对象: 
CreateFile() - 读写邮槽: 
ReadFile/WriteFile - 获取邮槽信息: 
GetMailslotInfo 
- 创建邮槽对象: 
 
快照
- 进程快照(得到是系统上所有的进程)
 - 模块快照(以进程为单位)
 - 线程快照(得到的是系统所有线程)
 - 堆快照(以进程为单位)
 
线程
- 创建线程的方式
 退出线程的方式
- 通过返回的方式正常退出(最理想)
 - 通过
ExitThread强制结束本线程 - 通过
TernamiteThread来结束指定线程 - 通过结束进程来结束所有的线程.
 
线程的切换
- 每个线程都有CPU时间片, 用完了时间片就被切换
 
异步IO
- 将同步IO模式改成异步IO的模式
在打开文件时,加上重叠IO的标志:FILE_FLAG_OVERLAPPED 
HANDLE hFile = INVALID_HANDLE_VALUE;hFile = CreateFile(L"002_异步IO.cpp",GENERIC_READ,/*读写方式:只读*/FILE_SHARE_READ,/*共享方式: 共享读*/NULL,/*安全描述符*/OPEN_EXISTING,/*创建标志:存在时才打开*/FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,/*文件属性和标志:正常属性|重叠IO标志 */NULL);
以重叠方式打开的句柄拥有一下特性:
句柄变成了可等待的状态
- 有信号 : 当有一个IO任务被完成,就变成有信号.
 - 无信号 : 默认无信号.
 
句柄不能使用文件读写位置了.
- 不能使用SetFilePointer来设置文件的读写位置.
 - 调用ReadFile或WriteFile的时候, 也不会使用文件读写位置来定义要读写的文件内容.
 - 只能使用OVERLAPPED的结构体来指定文件的读写位置.
 
投递IO任务
- 通过ReadFile来投递一个读取的IO任务
 - 通过WriteFile来投递一个写入的IO任务.
 
typedef struct _OVERLAPPED {ULONG_PTR Internal;// [输出]保存IO任务的错误码ULONG_PTR InternalHigh;//[输出]保存IO任务的完成的字节数union {struct {DWORD Offset;//[输入]用于指定文件读写位置的低32位DWORD OffsetHigh;//[输入]用于指定文件读写位置的高32位} DUMMYSTRUCTNAME;PVOID Pointer;} DUMMYUNIONNAME;HANDLE hEvent;//[输入]用于提供任务完成通知事件对象} OVERLAPPED, *LPOVERLAPPED;
- 通过结构体的offset来设置从文件中哪个位置开始读/写
 - 当系统完成了这个IO任务之后, 就会将处理结果(错误码)填写到结构体的Internal, 将具体读写了多少字节的内容写入到结构体的InternalHigh字段.
 - 系统完成IO任务之后, 如果hEvent字段值不为NULL, 就说明这个字段是有一个事件对象的, 那么系统会将这个事件对象设置为有信号状态.
 
获取IO完成通知
根据文件句柄的信号状态来判断
- 缺点 : 如果一个文件同时存在多个IO任务, 只要其中一个任务被完成了, 文件句柄就变成有信号状态,无法判断是哪个IO被完成了.
 
使用事件对象信号状态来判断
- 每个IO任务都有一个重叠IO结构体来配置信息
 - 每个IO任务都会配有一个事件对象. 哪个事件对象被设置成有信号了, 就说明哪个IO任务被完成了.
 - 要等待事件对象的信号时, 需要创建线程等待. 缺点: 如果IO任务很多,就说明要等待的事件也很多, 就需要创建大量线程线程等待, 造成效率低下.
 
使用扩展版的API:
- ReadFileEx
 - WriteFileEx
 - 扩展版的函数能够接收一个完成函数的回调函数.
 - 当IO任务被系统底层处理完毕之后, 这个回调函数就会被系统插入到线程的APC队列中.
 - 当线程被挂起(睡眠)的时候, 挂起之前,根据可警醒状态是否为真, 来决定调用APC队列中的函数.
 - 缺点: 如果在程序中没有调用Sleep或其它等待函数, 或者调用了,但是没有设置可警醒状态, 那么即使IO任务被完成了,完成回调函数也不会被调用.
 
通过完成端口来等待IO任务
- 创建异步IO方式的文件对象
 - 创建一个完成端口对象
 - 将完成端口和文件对象进行绑定
 创建指定个数线程, 在线程监视完成端口 完成列表的状态
- 通过API
GetQueuedCompletionStatus来获取完成列表的状态 
- 通过API
 - 发起异步IO任务.
 
事件对象
- 内核对象
 通过CreateEvent来创建
- 可以配置手动使用还是自动使用
 - 可以配置初始化是否有信号
 - 通过
SetEvent将事件设置为有信号 - 通过
ResetEvent重置事件对象的信号(设置为没有信号) 
通过
WaitForSingleObject来等待它的信号- WaitForSingleObject还会进一步修改被等待的事件对象的信号 : 从无信号开始阻塞等待,知道事件对象有信号之后就从阻塞状态中返回. 返回前,会顺手将事件对象设置为无信号.
 
