异步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完成端口
待续