异步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,);
    wcout<<L"FileSize:"<<dwFileSize<<endl;
    char * pFileContent = new char[];
    DWORD dwReaded = ;
    OVERLAPPED o_Read = {};
    DWORD bReadDone = ::ReadFile(hFile,
    pFileContent,
    ,
    &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,);
    wcout<<L"FileSize:"<<dwFileSize<<endl;
    LARGE_INTEGER liDis = {};
    LARGE_INTEGER liRet = {};
    ::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
    wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
    char * pFileContent = new char[];
    memset(pFileContent,'z',);
    DWORD dwReaded = ;
    OVERLAPPED o_Write = {};
    o_Write.Offset = liRet.LowPart;
    o_Write.hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
    DWORD bReadDone = ::WriteFile(hFile,
    pFileContent,
    ,
    &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,);
    wcout<<L"FileSize:"<<dwFileSize<<endl;
    LARGE_INTEGER liDis = {};
    LARGE_INTEGER liRet = {};
    ::SetFilePointerEx(hFile,liDis,&liRet,FILE_END);
    wcout<<L"PreWrite File Pos:"<<liRet.LowPart<<endl;
    char * pFileContent = new char[];
    memset(pFileContent,'g',);
    DWORD dwReaded = ;
    OVERLAPPED o_Write = {};
    o_Write.Offset = liRet.LowPart;
    DWORD bReadDone = ::WriteFileEx(hFile,
    pFileContent,
    ,
    &o_Write,
    FileIOCompletionRoutine); ::CloseHandle(hFile);
    SleepEx(,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 ;
    }
    else if(dw == WAIT_IO_COMPLETION)
    {
    wcout<<L"QueueUserApc Forced us out of a wait state"<<endl;
    return ;
    }
    return ;
    }
    void Test4()
    {
    //利用QueueUserApc来停止线程等待
    HANDLE hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);
    HANDLE hThread = (HANDLE) _beginthreadex(NULL,,ThreadFunc,hEvent,,NULL);
    Sleep();
    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,,NULL,CREATE_NEW,FILE_FLAG_OVERLAPPED,NULL); //创建完成端口
    HANDLE hIOCP=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,,);
    if(hIOCP==NULL)
    {
    printf("完成端口创建失败!");
    } //绑定完成端口
    CreateIoCompletionPort(hSrcFile,hIOCP,READ_KEY,);
    CreateIoCompletionPort(hDstFile,hIOCP,WRITE_KEY,); OVERLAPPED ov={};
    PostQueuedCompletionStatus(hIOCP,,WRITE_KEY,&ov);
    OVERLAPPED ovSrc={};
    OVERLAPPED ovDes={};
    ULONG_PTR CompletionKey;
    BYTE* pBuffer=new BYTE[BUFFERSIZE];
    int i=;
    int j=;
    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,,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 ;
    }

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

  1. windows核心编程 第8章201页旋转锁的代码在新版Visual Studio运行问题

    // 全局变量,用于指示共享的资源是否在使用 BOOL g_fResourceInUse = FALSE; void Func1() { //等待访问资源 while(InterlockedExcha ...

  2. windows核心编程 第5章job lab示例程序 解决小技巧

    看到windows核心编程 第5章的最后一节,发现job lab例子程序不能在我的系统(win8下)正常运行,总是提示“进程在一个作业里”         用process explorer程序查看 ...

  3. Windows核心编程 第十一章 线程池的使用

    第11章 线程池的使用 第8章讲述了如何使用让线程保持用户方式的机制来实现线程同步的方法.用户方式的同步机制的出色之处在于它的同步速度很快.如果关心线程的运行速度,那么应该了解一下用户方式的同步机制是 ...

  4. Windows核心编程 第七章 线程的调度、优先级和亲缘性(下)

    7.6 运用结构环境 现在应该懂得环境结构在线程调度中所起的重要作用了.环境结构使得系统能够记住线程的状态,这样,当下次线程拥有可以运行的C P U时,它就能够找到它上次中断运行的地方. 知道这样低层 ...

  5. windows核心编程---第六章 线程的调度

    每个线程都有一个CONTEXT结构,保存在线程内核对象中.大约每隔20ms windows就会查看所有当前存在的线程内核对象.并在可调度的线程内核对象中选择一个,将其保存在CONTEXT结构的值载入c ...

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

    内存映射文件主要用于以下三种情况: 系统使用内存映射文件载入并运行exe和dll,这大量节省了页交换文件的空间以及应用程序的启动时间 开发人员可以使用内存映射文件来访问磁盘上的数据文件.这使得我们可以 ...

  7. Windows核心编程 第十七章 -内存映射文件(下)

    17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...

  8. Windows核心编程 第六章 线程基础知识 (上)

    第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...

  9. windows核心编程---第七章 用户模式下的线程同步

    用户模式下的线程同步 系统中的线程必须访问系统资源,如堆.串口.文件.窗口以及其他资源.如果一个线程独占了对某个资源的访问,其他线程就无法完成工作.我们也必须限制线程在任何时刻都能访问任何资源.比如在 ...

  10. 《Windows核心编程》第九章——用内核对象进行线程同步

    先举一个有bug的例子: #include <iostream> #include <windows.h> #include <process.h> using n ...

随机推荐

  1. 夺命雷公狗---DEDECMS----15dedecms首页栏目列表页导航部分完成

    我们在点击导航页面的连接时候我们需要我们的连接跳到指定的模版页面,而不是随便跳到一个指定的A连接标签: 所以我们首先要将前端给我们的栏目列表模版拷贝到目录下,然后就可以创建栏目列表页面了,但是名字我们 ...

  2. enum与typedef enum的用法

    一,两者的用法 枚举类型定义用关键字enum标识,形式为: enum 标识符 { 枚举数据表 }:枚举数据(枚举常量)是一些特定的标识符,标识符代表什么含义,完全由程序员决定.数据枚举的顺序规定了枚举 ...

  3. yii2中表单的字段标签名称

    1.以登陆页面为例,默认是英文的,在loginForm.php中添加attributeLabels,可以变成中文 具体代码如下: public function attributeLabels(){  ...

  4. oracle中清空表数据的两种方法

    1.delete from t 2 .truncate table t 区别: 1.delete是dml操作:truncate是ddl操作,ddl隐式提交不能回滚 2.delete from t可以回 ...

  5. 好用的SSH客户端 good SSH client recommended

    对于经常性地要登录服务器的同志们,选择一款优秀的SSH客户端非常有必要,不仅可以提高效率,而且赏心悦目,宅的几率更大.呵呵,我就是i一枚.很出名的就是PuTTY(Windows,Linux都有的), ...

  6. fflush函数的深入理解

    本人昵称sky,欢迎与各位多多交流学习 这样的c程序想必大家都不陌生,fflush()这个函数有清除输入输出缓存的功能,那很多人就会问了,什么是清除输入输出缓存呢? 其实就是我们在printf输出的时 ...

  7. oracle 数据泵 详解

    导出数据 1)按用户导 expdp scott/tiger@orcl schemas=scott dumpfile=expdp.dmp DIRECTORY=dir logfile=expdp.log ...

  8. [转]centos中wget的使用方法

    本文转自 http://www.cnblogs.com/chusiping/archive/2011/11/10/2243805.html 和 http://www.jb51.net/os/RedHa ...

  9. 日常css和js小知识点记录

    2015-6-29 1.<meta name="viewport" content="width=device-width,user-scalable=no&quo ...

  10. 转Class.forName()用法详解

    主要功能 Class.forName(xxx.xx.xx)返回的是一个类 Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类, 也就是说JVM会执行该类的静态代码段 ...