异步IO操作与同步操作区别:
- 在CreateFile里的FILE_FLAG_OVERLAPPED标志
- 异步操作函数LPOVERLAPPED参数
接收IO请求完成通知
- 触发设备内核对象
缺点:同一个设备内核对象有可能进行多次读写操作,这样第一个完成这个设备内核对象就会被触发,所以这种方式不可以使用于这种情形
void Test1() { HANDLE hFile = ::CreateFile(_T("aaa.txt"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if(!hFile) { wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl; return ; } DWORD dwFileSize = ::GetFileSize(hFile,0); wcout<<L"FileSize:"<<dwFileSize<<endl; char * pFileContent = new char[10000000]; DWORD dwReaded = 0; OVERLAPPED o_Read = {0}; DWORD bReadDone = ::ReadFile(hFile, pFileContent, 10000000, &dwReaded, &o_Read); DWORD dwError = ::GetLastError(); if(!bReadDone && (dwError == ERROR_IO_PENDING)) { WaitForSingleObject(hFile,INFINITE); bReadDone = TRUE; } if(bReadDone) wcout<<L"I/O Code:"<<o_Read.Internal<<" TransedBytes:"<<o_Read.InternalHigh<<endl; else wcout<<"Error:"<<::GetLastError()<<endl; ::CloseHandle(hFile); delete [] pFileContent; }
- 触发事件内核对象
void Test2() { HANDLE hFile = ::CreateFile(_T("aaa.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if(!hFile) { wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl; return ; } DWORD dwFileSize = ::GetFileSize(hFile,0); wcout<<L"FileSize:"<<dwFileSize<<endl; LARGE_INTEGER liDis = {0}; LARGE_INTEGER liRet = {0}; ::SetFilePointerEx(hFile,liDis,&liRet,FILE_END); wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl; char * pFileContent = new char[10000000]; memset(pFileContent,'z',10000000); DWORD dwReaded = 0; OVERLAPPED o_Write = {0}; o_Write.Offset = liRet.LowPart; o_Write.hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL); DWORD bReadDone = ::WriteFile(hFile, pFileContent, 10000000, &dwReaded, &o_Write); DWORD dwError = ::GetLastError(); if(!bReadDone && (dwError == ERROR_IO_PENDING)) { WaitForSingleObject(o_Write.hEvent,INFINITE); bReadDone = TRUE; } if(bReadDone) wcout<<L"I/O Code:"<<o_Write.Internal<<" TransedBytes:"<<o_Write.InternalHigh<<endl; else wcout<<"Error:"<<::GetLastError()<<endl; ::CloseHandle(hFile); delete [] pFileContent; }
- 可提醒IO
void Test3() { //可提醒IO HANDLE hFile = ::CreateFile(_T("aaa.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if(!hFile) { wcout<<L"CreateFile Failed ErroCode:"<<::GetLastError()<<endl; return ; } DWORD dwFileSize = ::GetFileSize(hFile,0); wcout<<L"FileSize:"<<dwFileSize<<endl; LARGE_INTEGER liDis = {0}; LARGE_INTEGER liRet = {0}; ::SetFilePointerEx(hFile,liDis,&liRet,FILE_END); wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl; char * pFileContent = new char[10000000]; memset(pFileContent,'g',10000000); DWORD dwReaded = 0; OVERLAPPED o_Write = {0}; o_Write.Offset = liRet.LowPart; DWORD bReadDone = ::WriteFileEx(hFile, pFileContent, 10000000, &o_Write, FileIOCompletionRoutine); ::CloseHandle(hFile); SleepEx(10000,TRUE); delete [] pFileContent; }
可提醒IO的优劣:
(1)由于回调函数的原因,最终不得不把大量信息放在全局变量中。使代码变的更加复杂
(2)发出请求线程和完成处理必须是同一线程,没有达到线程负载均衡
可提醒IO相关函数
(1)QueueUserAPC函数
a.这个函数允许我们手动增加APC项。
b.可以强制线程退出等待状态比如WaitForSingleObjectEx 以下是示例代码
VOID WINAPI APCFunc(ULONG_PTR pvParam) { //Nothing To Do } UINT WINAPI ThreadFunc(PVOID pvParam) { wcout<<L"start Wait...."<<endl; DWORD dw = ::WaitForSingleObjectEx(pvParam,INFINITE,TRUE); if(dw == WAIT_OBJECT_0) { wcout<<L"Event signaled"<<endl; return 0; } else if(dw == WAIT_IO_COMPLETION) { wcout<<L"QueueUserApc Forced us out of a wait state"<<endl; return 0; } return 0; } void Test4() { //利用QueueUserApc来停止线程等待 HANDLE hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL); HANDLE hThread = (HANDLE) _beginthreadex(NULL,0,ThreadFunc,hEvent,0,NULL); Sleep(5000); QueueUserAPC(APCFunc,hThread,NULL); WaitForSingleObject(hThread,INFINITE); CloseHandle(hThread); CloseHandle(hEvent); }
- I/O完成端口
待续
void Test5() { //I/O完成端口 TCHAR SrcFileName[MAXSIZE]; TCHAR DesFileName[MAXSIZE]; cout<<"请输入源文件名:\n"; wcin>>SrcFileName; cout<<"请输入目的文件名:\n"; wcin>>DesFileName; HANDLE hSrcFile=CreateFile(SrcFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_FLAG_OVERLAPPED,NULL); if(hSrcFile==INVALID_HANDLE_VALUE) { printf("文件打开失败!"); } DWORD FileSizeHigh; DWORD FileSize=GetFileSize(hSrcFile,&FileSizeHigh); HANDLE hDstFile=CreateFile(DesFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_FLAG_OVERLAPPED,NULL); //创建完成端口 HANDLE hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,4); if(hIOCP==NULL) { printf("完成端口创建失败!"); } //绑定完成端口 CreateIoCompletionPort(hSrcFile,hIOCP,READ_KEY,0); CreateIoCompletionPort(hDstFile,hIOCP,WRITE_KEY,0); OVERLAPPED ov={0}; PostQueuedCompletionStatus(hIOCP,0,WRITE_KEY,&ov); OVERLAPPED ovSrc={0}; OVERLAPPED ovDes={0}; ULONG_PTR CompletionKey; BYTE* pBuffer=new BYTE[BUFFERSIZE]; int i=0; int j=0; while(true) { DWORD nTransfer; OVERLAPPED* o; GetQueuedCompletionStatus(hIOCP,&nTransfer,&CompletionKey,&o,INFINITE); switch(CompletionKey) { case READ_KEY: //代表读取IO操作已经完成,进行下一步写入操作 WriteFile(hDstFile,pBuffer,o->InternalHigh,NULL,&ovDes); cout<<"write:"<<++i<<endl; ovDes.Offset+=o->InternalHigh; //if(ovDes.Offset== FileSize/1024 ) // return 0; break; case WRITE_KEY: //代表写入IO操作已经完成,进行下一步读取操作 memset(pBuffer,0,BUFFERSIZE*sizeof(BYTE)); if(ovSrc.Offset < FileSize)//文件读取未完成 { DWORD nBytes; if(ovSrc.Offset+BUFFERSIZE < FileSize) nBytes=BUFFERSIZE; else nBytes=FileSize-ovSrc.Offset; ReadFile(hSrcFile,pBuffer,nBytes,NULL,&ovSrc); cout<<"read:"<<++j<<endl; ovSrc.Offset+=nBytes; } else return ; break; default: break; } } return ; }