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

 

异步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 ;
    }

     

时间: 2024-11-09 06:21:29

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

《windows核心编程》 17章 内存映射文件

内存映射文件主要用于以下三种情况: 系统使用内存映射文件载入并运行exe和dll,这大量节省了页交换文件的空间以及应用程序的启动时间 开发人员可以使用内存映射文件来访问磁盘上的数据文件.这使得我们可以避免直接对文件IO操作和对文件内存进行缓存 进程间通讯 17.1 映射到内存的可执行文件和DLL 当一个线程调用CreateProcess的时候,系统会执行收入步骤: 1.判断exe位置,如果无法找到exe那么不会创建进程,这时会CreateProcess返回FALSE 2.创建一个新的进程内核对象

018_《Delphi下深入Windows核心编程》

<Delphi下深入Windows核心编程> Delphi 教程 系列书籍 (018) <Delphi下深入Windows核心编程> 网友(邦)整理 EMail: shuaihj@163.com 下载地址: Part1 Part2 Part3     书名: Delphi下深入Windows核心编程 作者: 飞思科技产品研发中心 出版社: 电子工业出版社 书号: 7505384023 出版日期:2003年1月 开本: 787*1092 1/16 页码: 525 版次: 2003年1

[原创/讨论][windows核心编程一外传]关于访问虚拟地址0的方法。

接上一篇 Windows 核心编程研究系列之一(改变进程 PTE) 内容 上一篇观赏地址 :http://community.csdn.net/Expert/topic/5124/5124747.xml?temp=.2832453 当然系统保证不让访问地址0出于一种保护的目的,是防止未初始化的指针读取数据.我说的访问地址0只是出于一种纯实现的目的,也不提倡大家这样做.说白了只是好玩罢了. 大家都知道在 windows 中读取/写入地址0的指令肯定会出错: // 写 0 地址的内容xor edx,

请教windows核心编程 ErrorShow程序例子问题

问题描述 请教windows核心编程 ErrorShow程序例子问题 刚刚学习win32 有个问题TCHAR buffer[100]; case WM_PAINT:{ hdc = BeginPaint (hwnd &ps) ; DWORD systemLocale = MAKELANGID(LANG_NEUTRAL SUBLANG_NEUTRAL); DWORD dwError = 1; HLOCAL hlocal = NULL; BOOL fOk = FormatMessage( FORMAT

Windows 核心编程研究系列之一(-改变进程PTE属性-)[已补完]

  Windows 核心编程研究系列之一 -改 变 进 程 PTE 属性-              这是我研究windows 核心编程的第一篇正式文章,之所以叫核心编程而不叫内核编程,是我觉得从字面上来看核心(core)比内核(kernel)更靠近windows中心,当然只是偶本人的看法的拉.          我们知道在 win NT 中,系统把每个进程的虚拟4G空间分为两大部份,低2G归用户所有,高2G归系统所有.用户不得访问系统的空间,连读都不行,更别说写了!低2G的用户空间也并不是都能

《windows核心编程系列》二谈谈ANSI和Unicode字符集 .

http://blog.csdn.net/ithzhang/article/details/7916732转载请注明出处!! 第二章:字符和字符串处理     使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也就是说每个字符编码为两个字节.65535个字符可以表示世界上大部分的语言.为了软件使国际化大家再编程时应该使用unicode字符集.由于原来学过c语言,不习惯

chHANDLE_DLGMSG(windows核心编程)讲解

看完<Windows程序设计>后开始看<windows核心编程>, 结果看第一个案例的时候就很惊人的发现,Jeffery大牛的代码很深奥.乍一看好像没有包含<windows.h>. 看看包含的头文件发现,CmnHdr.h中已经包含了<windows.h>.而CmnHdr.h中的代码更吓人,如果没有讲解,不知道怎么看才好.后来才知道原来书的最后有专门的搭建环境的介绍,基本上全面的讲解了CmnHdr.h的东西.   CmnHdr.h中包含了大牛的很多自己的东西.

《windows 核心编程》 -探索虚拟内存

14.1 系统信息 操作系统中有许多值 是由系统所运行的主机所决定的.如果页面大小和分配粒度等.我们决对不应该在代码中将这些值写死. 此函数得到系统信息VOID GetSystemInfo(LPSYSTEM_INFO ps) 如果想得到机器中与处理器有关的详细信息可以调用GetLogicalProcesorInfomation函数 为了让32位应用程序在64位版本的Windows运行,Microsoft提供了一个称为windows 32 bit On Windows 64 的模拟层又称为WOW.

《windows核心编程》–Windows内存体结构(二)

13.6页面保护属性     内存页面保护属性有 PAGE_NOACCESS.PAGE_READONLY.PAGE_READWRITE.PAGE_EXECUTE.PAGE_EXECUTE_READ.PAGE_EXECUTE_READWRITE.PAGE_WRITECOPY.PAGE_EXECUTE_WRITECOPY.这些保护分别表示什么http://127.0.0.1:47873/help/1-3788/ms.help?method=page&id=09839DB7-2118-4A7D-A70