日期:2014-05-17  浏览次数:20886 次

Windows 异步IO和 完成端口(IOCP)

 

见过网上好多的完成端口和网络通信的文章,呵呵,这里就简单的说说文件异步IO和完成端口,这里仅仅说说读取操作。下面是一些总结,很少有人提及,认真的看过MSDN文档之后得出的,欢迎指正。

  1. 要对文件异步IO操作,需要在文件创建的时候指定FILE_FLAG_OVERLAPPED属性的;
  2. 异步ReadFileEx是不能读取和IO完成端口绑定的文件句柄的;
  3. 异步ReadFileEx对OVERLAPPED的hEvent忽视;
  4. 异步完成后可以出发回调,回调接口需要指定WINAPI属性,实际上就是_stdcall,如果不指定则默认是_cdecl属性,回调完成后,会崩溃的;
  5. 最后需要等待。

这里简单的附上一段异步代码:

 

#include <process.h>
#include <Windows.h>

VOID WINAPI rt(
  __in     DWORD dwErrorCode,
  __in     DWORD dwNumberOfBytesTransfered,
  __inout  LPOVERLAPPED lpOverlapped
)
{
    printf("rt call back\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
    OVERLAPPED *ol = new OVERLAPPED;
    memset(ol, 0, sizeof *ol);

    HANDLE file = CreateFile("ReadMe.txt", 
        GENERIC_READ, 
        0, 
        NULL, 
        OPEN_EXISTING , 
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED ,
        NULL);

    if(file == INVALID_HANDLE_VALUE)
    {
        goto mem_free1;
    }

    size_t buf_len = 1024;
    char *buf = new char[buf_len];

    if(!buf)
    {
        goto mem_free1;
    }

    if(!ReadFileEx(file, buf, buf_len, ol, rt))
    {
        goto mem_free;
    }

    SleepEx(INFINITE, TRUE);

mem_free:
    delete []buf;

mem_free1:
    delete ol;    
    CloseHandle(file);

	return 0;
}

 

对于ReadFile,主线程在触发异步操作之后,就需要有另外的线程来做辅助工作,可以使用event事件,这里主要介绍完成端口,没有多少好说的,也贴上代码吧:

 

#include <process.h>
#include <windows.h>

//创建一个IO完成端口
HANDLE CreateNewCompletionPort(DWORD dwNumberOfConcurrentThreads)
{
    return( CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, dwNumberOfConcurrentThreads));
}

//将设备与完成端口管理起来
BOOL AssociateDeviceWithCompletionPort(HANDLE hCompletionPort, HANDLE hDevice,  DWORD dwCompletionKey) 
{
    HANDLE h = CreateIoCompletionPort(hDevice,   hCompletionPort, dwCompletionKey,   0);
    return (h == hCompletionPort);
}

void reader(void *in)
{
    HANDLE     port    = (HANDLE)in;
    DWORD      rcv_len = 0;
    ULONG_PTR  my_key  = 0;
    OVERLAPPED *ol1    = NULL;

    while(1)
    {
        if(!GetQueuedCompletionStatus(port, &rcv_len, &my_key, &ol1, INFINITE))
        {
            int err = GetLastError();
            continue;
        }
        else
        {
            _endthread();
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    int key = 12345;

    HANDLE port = CreateNewCompletionPort(4);

    if(!port)
    {
        int err = GetLastError();
        return 0;
    }

    HANDLE file = CreateFile("ReadMe.txt", 
        GENERIC_READ, 
        0, 
        NULL, 
        OPEN_EXISTING , 
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED ,
        NULL);

    if(file == INVALID_HANDLE_VALUE)
    {
        CloseHandle(port);
    }

    OVERLAPPED *ol = new OVERLAPPED;
    memset(ol, 0, sizeof *ol);    

    if(!AssociateDeviceWithCompletionPort(port, file, key))
    {
        int err = GetLastError();

        CloseHandle(port);
        CloseHandle(file);

        delete ol;

        return 0;
    }

    int buf_len = 1000;
    char *buf = new char[buf_len];

    if(!buf)
    {
        CloseHandle(port);
        CloseHandle(file);

        delete ol;
        return 0;
    }

    HANDLE h_thread = (HANDLE)_beginthread(reader, 0, port);

    if(!ReadFile(file, buf, buf_len, NULL, ol))
    {