1.使用设备内核对象进行提醒
进行异步文件操作的提醒
2.使用事件内核对象提醒
提醒同步以及交互,是一种完全不同的的提醒
3.可提醒IO
不可跨线程的
4.I/O完成端口
使用最广泛
示例
#include<windows.h> int main() { HANDLE hFile =CreateFile(TEXT("demo.txt",GENERIC_READ|GENERAIC_WRITE,FILE_SHARE,nullptr,OPEN_ALWAYS,FILE_FALG_OVERLAPPED,NULL); if(hFile != INVALID_HANDLE_VALUE) { //read BYTE bReadBuffer[100]={0}; OVERLAPPED oRead ={0}; oRead.Offset=0; oRead.hEvent = CreateEvent(nullptr,TRUE,FALSE,TEXT("ReadEvent"));//事件内核对象,是独立于程序之外的,属于操作系统的,通过name在各个程序中使用 ReadFile(hFile,bReadBuffer,sizeof(bReadBuffer),nullptr,&oRead); //write BYTE bWriteBuffer[10]={0}; OVERLAPPED oWrite ={0}; oWrite.Offset=0; oWrite.hEvent = CreateEvent(nullptr,TRUE,FALSE,TEXT("WriteEvent"));//事件内核对象,是独立于程序之外的,属于操作系统的,通过name在各个程序中使用 WriteFile(hFile,bWriteBuffer,sizeof(bWriteBuffer),nullptr,&oWrite); //做其它的事情...异步最好的地方,就在于不会发生阻塞 //其它线程 HANDLE hOverLapped[2]={0}; hOverLapped[0]=oRead.hEvent; hOverLapped[1]=oWrite.hEvent; while (TRUE) { DWORD dwCase = WaitForMultipleObjects(2, hOverLapped, FALSE, INFINITE);//进行事件对象的提醒 switch (dwCase - WAIT_OBJECT_0) { case 0: // 读完成 break; case 1: // 写完成 break; } } } else { //GetLastError } }程序领空与系统领空
系统领空是所有程序共用的,事件内核对象存在于系统领空,那么程序与程序之间的交互就可以通过事件内核对象,也可以通过事件内核对象中的对象来判断状态
事件内核对象提醒:
发送请求 做自己的事情 判断请求是否完成
可提醒IO:
发送请求 完成后,操作系统提醒我
APC机制 进程是工厂,线程是工人,在线程的内部,它有一个机制:APC
当工人闲的时候(前提),来做APC列表中的事情
当线程空闲的时候(线程为可提醒状态下),自动执行APC列表中的事情
比如:MessageBox会导致线程阻塞,当这个线程阻塞的时候,看上去线程闲下来了,但是并不是可提醒状态,在windows中,只有Wait函数、Sleep函数才能真正的“闲”下来
相当于一个不定时的定时器,APC不确定啥时候会被触发,但是只要触发就会去做事情
提醒IO就是依托于APC来做的
示例
#include<windows.h> int main() { HANDLE hFile =CreateFile(TEXT("demo.txt",GENERIC_READ|GENERAIC_WRITE,FILE_SHARE,nullptr,OPEN_ALWAYS,FILE_FLAG_OVERLAPPED,NULL)); if(hFile != INVALID_HANDLE_VALUE) { CONST UINT unLen = 255; // Read OVERLAPPED oRead = {0};//此时里面的东西都不用设置,Offset可以设置,但是Event不能设置 oRead.Offset = 0; BYTE bReadBuf[unLen] = {0}; // 异步读取文件 通过可提醒IO ReadFileEx(hFile, bReadBuf, unLen, &oRead,FileIOCommpletionRoutineRead); // 可以使得线程为可提醒状态的函数 // SleepEx // Wait.... 函数 SleepEx(100, TRUE);//BOOL值代表,当SleepEx被调用的时候,是否把自己设置为空闲状态,不设置为TRUE的时候,也就相当于阻塞但非可提醒状态,此时APC不会被调用,所以这个BOOL值很重要 } else { //GetLastError } }可提醒不是那么好用:
回调函数参数太少,作用有限,可通过全局来传入参数,但是逻辑会混乱
操作异步IO最为方便、科学的方式
以上三种都是一个线程之内来做的事情,可提醒IO可以让别的线程来做这件事情,但是做起来较为麻烦,使用的是串行模型来进行异步IO操作
异步IO操作最适合的是并行模式,是多线程。
windows是多进程的
但是在单核时代,是模拟出来的多进程,只是CPU运行速度快,我们没感觉而已
多核下,每个核都可以运行一个线程(无切换), 也可以进行线程切换
多进程
如果进程只有一个线程,那么一个程序只能做一件事情,如果需要做两件事情,那么就需要两个进程,但是,两个进程都会有一个内核对象,如果两个进程进行交互的话,那么会耗费大量的资源,所以在进程之下设计了线程
多线程
线程之间的切换也会耗费资源,只是比线程之间切换要好点。核心数增加之后,并行模式开始流行起来
完成端口是天生的并行模式,使用它来异步操作大文件的时候会更快