异步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. 关于CentOS 7.1后期维护的问题

    1.问题描述:在使用ssh服务远程登录的时候,当显示输入密码,特别特别的慢,刚刚搭建 服务器的时候还很正常,经过一个假期我实在忍不了它了,故决定解决此问题.服务器系统:CentOS 7.1 解决方式: ...

  2. 【crunch bang】论坛tint2配置讨论贴

    地址: http://crunchbang.org/forums/viewtopic.php?id=3232

  3. Mysql子查询、关联查询

    mysql中update.delete.install尽量不要使用子查询 一.mysql查询的五种子句         where(条件查询).having(筛选).group by(分组).orde ...

  4. UIViewController卸载过程(ios6.0之前)

    1.当应用程序收到内存不足的警告之后,程序中所有存在的UIViewController都会收到didReceiveMemoryWarning调用消息,目的是将当前不显示的View释放掉,缓解内存压力. ...

  5. 如何在图像处理工具包ImagXpress中对图像进行捕捉、复制和粘贴

    如何在在ImagXpress中进行图像的捕捉. 复制和粘贴呢?下面详细来看一下,在多种情况下,图和实现这些操作. 捕捉屏幕图像 捕捉通过ImageXView窗口绑定的屏幕范围,以及保存到一个Image ...

  6. Intel+Ardruino 101

    为了传说中的那啥, 啊, 嗯.. #include <CurieBLE.h>const int ledPin = 13; // set ledPin to on-board LED  LE ...

  7. web.xml完整配置

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java ...

  8. 如何获取各大平台的播放地址(获得优酷的m3u8播放地址)为例

    1.打开safari 2.在顶部(黑色小苹果)旁边,点击safari. 3.打开里面的 偏好设置. 4.在高级 中 找到 “在菜单栏中显示开发菜单” 并打勾. 5.关闭窗口后,可以发现safari 顶 ...

  9. 在Linux下搭建Git服务器的方法是什么样?

    第一步 安装git:可以通过命令的方式快速安装,不同的linux的安装方法可能不一样,我的是采用的yum方法.ubuntu可以用apt-get命令.sudo yum install git 第二步 添 ...

  10. HDU 2444:The Accomodation of Students(二分图判定+匹配)

    http://acm.hdu.edu.cn/showproblem.php?pid=2444 题意:给出边,判断这个是否是一个二分图,并求最大匹配. 思路:先染色法求出是否是一个二分图,然后再匈牙利求 ...