异步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. RobotFramework 安装配置(一)

    服务器接口的测试框架的选择,最后选中了 RobotFramework ,原因一:能有效的管理测试用例,,支持批量执行,能实现关键字驱动或者数据驱动.原因二:支持测试人员可以使用Python和java创 ...

  2. [php]gd图像

    <?php /* 处理图像 */ /* {php5} 动态图像的处理更容易. 在 php.ini中就包含了GD扩展包, 去掉 其中的注释即可. extension=php_gd2.dll 其中 ...

  3. 【fedora】强制解除yum锁定

    运行yum makecache时出现yum update时候出现Another app is currently holding the yum lock解决方法yum被锁定了. 可以通过执行 rm ...

  4. 【转】Web UI自动化测试原理

    目前市面上有很多Web UI自动化测试框架,比如WatiN, Selinimu,WebDriver,还有VS2010中的Coded UI等等.  这些框架都可以操作Web中的控件,模拟用户输入,点击等 ...

  5. Spark实战1:shell+独立App使用总结

    Spark改进了Hadoop执行非流式算法的需要多次IO的缺陷,Spark的所有操作都是基于RDD弹性分布式数据集这种数据结构的,对RDD的操作主要的操作包括transform和action两种操作. ...

  6. java总结第三次//类和对象2、3

    四.类和对象2 主要内容:Java类的继承.方法的重写.覆盖.访问控制.super 关键字.多态性及其应用 1.继承 要求:Java只支持单继承,不允许多重继承 一个子类只能有一个父类 一个父类可以派 ...

  7. STM32外部中断.

    void EXTIX_Init(void){     EXTI_InitTypeDef EXTI_InitStructure;    NVIC_InitTypeDef NVIC_InitStructu ...

  8. Ubuntu 下配置ftp服务端

    安装sudo apt-get install pure-ftpdsudo netstat –ano | grep “21”查看21端口是否已开启.完成安装后,就可以用Ubuntu系统的用户名和密码登陆 ...

  9. 【原创】Nexus搭建Maven私服

    前言: 公司一般都有个自己的私服来管理各种jar包,原因大概有这么3个,分别是: 1.有的公司不能访问外网,只能通过私服来管理jar包和插件: 2.公司网速比较慢,通过公司的私服来获取jar包比较快: ...

  10. C#:关联程序和文件

    一.关联代码 /// <summary> /// 关联程序和类型 /// </summary> private void RegFileExt() { try { string ...