尽管现在网络上关于IO Completion Port的文章多如牛毛,但绝大多数是以socket为例的。而socket I/O比File I/O要复杂得多,导致相应的例子也比较复杂。下面是一个使用IO Completion Port实现File I/O的程序。为了简单,没有错误处理。
1 #include <iostream> 2 #include <string.h> 3 #include "windows.h" 4 5 using namespace std; 6 7 // 文件操作次数 8 #define NR_FILE_OP_TIMES 4 9 // 每次IO的数据量 10 #define BUFFER_SIZE (1024 * 1024) 11 12 static DWORD WINAPI ThreadFunc(LPVOID param); 13 14 int main() 15 { 16 HANDLE hFile = CreateFile("test.dat", 17 GENERIC_READ | GENERIC_WRITE, 18 FILE_SHARE_READ, 19 0, 20 CREATE_ALWAYS, 21 FILE_FLAG_OVERLAPPED, 22 0); 23 24 // 初始化数据缓冲区 25 char* ppBuf[NR_FILE_OP_TIMES]; 26 for(int i = 0; i < NR_FILE_OP_TIMES; i++) 27 { 28 ppBuf[i] = new char[BUFFER_SIZE]; 29 memset(ppBuf[i], i, BUFFER_SIZE); 30 } 31 32 // 初始化overlapped结构 33 OVERLAPPED overlapped[NR_FILE_OP_TIMES]; 34 memset(overlapped, 0, sizeof(OVERLAPPED) * NR_FILE_OP_TIMES); 35 36 // 创建completion port 37 HANDLE hPort = CreateIoCompletionPort(hFile, 0, 0, 0); 38 39 // 创建Threads 40 HANDLE hThread[NR_FILE_OP_TIMES]; 41 for(int i = 0; i < NR_FILE_OP_TIMES; i++) 42 { 43 // Create Thread Pool 44 hThread[i] = CreateThread(0, 0, ThreadFunc, &hPort, 0, 0); 45 } 46 47 // 启动File I/O 48 DWORD bytesWritten; 49 HANDLE hEvent[NR_FILE_OP_TIMES]; 50 for(int i = 0; i < NR_FILE_OP_TIMES; i++) 51 { 52 overlapped[i].Offset = BUFFER_SIZE * i; 53 hEvent[i] = CreateEvent(0, TRUE, FALSE, 0); 54 overlapped[i].hEvent = hEvent[i]; 55 WriteFile(hFile, ppBuf[i], BUFFER_SIZE, &bytesWritten, &(overlapped[i])); 56 } 57 58 // 等待I/O完成 59 WaitForMultipleObjects(4, hEvent, TRUE, INFINITE); 60 61 // Cleanup 62 for(int i = 0; i < NR_FILE_OP_TIMES; i++) 63 { 64 delete ppBuf[i]; 65 CloseHandle(hThread[i]); 66 } 67 CloseHandle(hPort); 68 CloseHandle(hFile); 69 return 0; 70 } 71 72 static DWORD WINAPI ThreadFunc(LPVOID param) 73 { 74 HANDLE hPort = *((HANDLE *)param); 75 76 OVERLAPPED* pOverlapped; 77 DWORD bytesTransferred; 78 DWORD key; 79 80 GetQueuedCompletionStatus(hPort, 81 &bytesTransferred, 82 &key, 83 &pOverlapped, 84 INFINITE); 85 86 // 打印出I/O相关信息,设置Event,然后这个Thread就退出了。 87 cout << "Bytes transferred from " << pOverlapped->Offset << ", length " << bytesTransferred << endl; 88 89 SetEvent(pOverlapped->hEvent); 90 91 return 0; 92 }
下面是运行结果:
从运行结果看,写入顺序是1 2 3 4,完成顺序是1 2 4 3。