• 异步设备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<<"请输入源文件名:
      ";
          wcin>>SrcFileName;
      
          cout<<"请输入目的文件名:
      ";
          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 ;
      }
  • 相关阅读:
    从零开始webpack4.x(五) js处理
    从零开始webpack4.x(四)样式loader
    从零开始webpack4.x(三)html插件
    从零开始webpack4.x(二)基础
    从零开始webpack4.x(一)介绍
    【转】react和vue渲染流程对比
    css3相关
    html5相关
    this指向
    整数划分问题(递归)
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/4278174.html
Copyright © 2020-2023  润新知