使用完成端口(IO Completion Port)读写文件

来源:互联网 发布:软件研发工程师t1 编辑:程序博客网 时间:2024/05/17 01:43

关于完成端口网上有许多文章.但是绝大多数的例子都是用在网络通信上.例如可以用其构建"scalable web server"之类的.在学习异步处理文件(overlapped IO,这里仅考虑处理本地文件)的时候知道异步操作完成后根据内核通知用户应用程序的情况不同可由4种方式来实现:内核对象(handle),事件内核对象(hEvent),,异步过程调用(apcs)完成端口(I/O completion port).前3种在网上有比较完整的实现.基于完成端口的不太多见.

我在这儿并不想十分深入的介绍完成端口的来龙去脉,事实上我对其理解也不算很深.我个人只是想知道使用完成端口的一个代码框架而已(简单的读写文件).关于此我有几点说明:

1.肯定有利用完成端口读写文件的很漂亮的解决方案,我这个只是自己的试验品,倘若有大牛对此有心得欢迎交流.

2.在利用异步读写文件的时候,假如这个文件的内容存放在cache中(这也是一个假设),ReadFile or WriteFile有可能不会使用异步那一套,直接按照普通的方法(同步的)进行读写.这个在msdn上有过解释点这儿.但是上面的解释并未覆盖完成端口这一块,意思就是这一块的处理我也并非官方,大家可以自由发挥.

3.其实完成端口这块主要是两个函数CreateIoCompletionPort和GetQueuedCompletionStatus.具体的函数解释请参考msdn.而且关于用法也并非我的代码中所展示的固定,大家同样可以自由发挥.例如CompletionKey这个参数就有很多玩法.

4.代码只演示了写文件.说多了,大家看代码吧,bug或者不当的地方请大家鞭笞.

 

#include "stdafx.h"#include "windows.h"#define IOCP_WRITE 1#define IOCP_FINISH 2HANDLE hWriteIOCP;typedef struct _OVERLAPIOINFO { OVERLAPPED overlapped; HANDLE hFile; } OVERLAPIOINFO;HANDLE CreateNewCompletionPort() { return CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); } BOOL AssociateFileCompletionPort(HANDLE hIoPort, HANDLE hFile, DWORD completionKey) { HANDLE h = CreateIoCompletionPort(hFile, hIoPort, completionKey, 0); return h == hIoPort; } DWORD WINAPI SaveFileWorkerThread(void *empty) { ULONG_PTR completionKey; BOOL completionStatus; DWORD bytesTransferred; DWORD err; OVERLAPPED *overlap; OVERLAPIOINFO *info; for (;;) { completionStatus = GetQueuedCompletionStatus(hWriteIOCP, &bytesTransferred, &completionKey, &overlap, INFINITE); err = GetLastError(); if (completionStatus)  { switch(completionKey) { case IOCP_WRITE: fprintf(stderr, "wrote %d bytes\n", bytesTransferred); break; case IOCP_FINISH: fprintf(stderr, "done!"); info = (OVERLAPIOINFO *) overlap; CloseHandle(info->hFile); free(info); return 0; } }  else  { if (overlap != NULL)  fprintf(stderr, "overlap not null"); else  if (err != WAIT_TIMEOUT) fprintf(stderr, "timeout"); } } } int _tmain(int argc, _TCHAR* argv[]){HANDLE hSaveFile,hWorker; OVERLAPIOINFO *saveFileOverlap; char buf[] = "hello"; hWriteIOCP = CreateNewCompletionPort(); hWorker = CreateThread(NULL, 0, SaveFileWorkerThread, NULL, 0, NULL); if ((hSaveFile = CreateFileA("F:\\test\\received.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL,  CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL)) == INVALID_HANDLE_VALUE) fprintf(stderr, "unable to create file\n"); saveFileOverlap = (OVERLAPIOINFO *) malloc(sizeof(*saveFileOverlap)); memset(&(saveFileOverlap->overlapped), 0, sizeof(saveFileOverlap->overlapped)); saveFileOverlap->hFile = hSaveFile; AssociateFileCompletionPort(hWriteIOCP, saveFileOverlap->hFile, IOCP_WRITE); if (!WriteFile(saveFileOverlap->hFile, buf, strlen(buf), NULL, &(saveFileOverlap->overlapped))) {if (GetLastError() != ERROR_IO_PENDING) fprintf(stderr, "error writing file\n"); }else{fprintf(stderr, "synchronous returned here\n");}PostQueuedCompletionStatus(hWriteIOCP, 0, IOCP_FINISH, &(saveFileOverlap->overlapped)); WaitForSingleObject(hWorker,INFINITE);CloseHandle(hWorker);return 0;   {