异步设备IO 《windows核心编程》第10章学习

  1. 云栖社区>
  2. 博客>
  3. 正文

异步设备IO 《windows核心编程》第10章学习

技术小阿哥 2017-11-27 14:18:00 浏览912
展开阅读全文

异步IO操作与同步操作区别:

  1. 在CreateFile里的FILE_FLAG_OVERLAPPED标志
  2. 异步操作函数LPOVERLAPPED参数

接收IO请求完成通知

  1. 触发设备内核对象 
    缺点:同一个设备内核对象有可能进行多次读写操作,这样第一个完成这个设备内核对象就会被触发,所以这种方式不可以使用于这种情形 
    复制代码
    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;
    }
    复制代码
  2. 触发事件内核对象 
    复制代码
    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;
    }
    复制代码
  3. 可提醒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);
    }
    
    
    
    
    复制代码
  4. 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 ;
    }
    复制代码

     

网友评论

登录后评论
0/500
评论
技术小阿哥
+ 关注