I/O完成端口

来源:互联网 发布:silk labo 知乎 编辑:程序博客网 时间:2024/04/29 22:56

I/O完成端口存在5个数据结构
1.设备列表 存放:设备句柄和I/O key
2.I/O完成队列 存放:I/O完成记录 先进先出
3.等待线程队列 存放:等待处理I/O完成记录 后进先出
4.已释放线程列表 存放:正在处理I/O完成记录的线程
5.已暂停线程列表 存放:挂起的线程

系统将异步I/O请求函数中请求完成后放入2中,检查4中正在运行的线程数是否低于并行数,是则唤醒3中线程。
PostQueuedCompletionStatus 用来将一个已完成的I/O通知追加到I/O完成端口的队列中。

如2中最初放入W1,W2,W3,W4 4个I/O完成记录
3中调用GetQueuedCompletionStatus 3中线程为T1,T2  取出W1,W2  处理方式是Readfile,T2->W1,T1->W2,处理完2中变为W3,W4,R1,R2 3中变为T1,T2 //如果CreateIoCompletionPort中最后并行数设为2
3中调用GetQueuedCompletionStatus 取出W3,W4  处理方式是Readfile,T2->W3,T1->W4 处理完2中变为R1,R2,R3,R4 3中变为T2,T1 //哪个线程先等待则先进入3中
3中调用GetQueuedCompletionStatus 取出R1,R2  处理方式是Writefile,T1->R1,T2->R2 处理完2中变为R3,R4,W5,W6 3中变为T2,T1
....

 

//EnsureCleanup.h/******************************************************************************Module:  EnsureCleanup.hNotices: Copyright (c) 2007 Jeffrey Richter & Christophe NasarrePurpose: These classes ensure object cleanup when an object goes out of scope.         See Appendix A.******************************************************************************/#pragma once   // Include this header file once per compilation unit///////////////////////////////////////////////////////////////////////////////#include <Windows.h>///////////////////////////////////////////////////////////////////////////////// Data type representing the address of the object's cleanup function.// I used UINT_PTR so that this class works properly in 64-bit Windows.typedef VOID (WINAPI* PFNENSURECLEANUP)(UINT_PTR);///////////////////////////////////////////////////////////////////////////////// Each template instantiation requires a data type, address of cleanup // function, and a value that indicates an invalid value.template<class TYPE, PFNENSURECLEANUP pfn, UINT_PTR tInvalid = NULL> class CEnsureCleanup {public:   // Default constructor assumes an invalid value (nothing to cleanup)   CEnsureCleanup() { m_t = tInvalid; }   // This constructor sets the value to the specified value   CEnsureCleanup(TYPE t) : m_t((UINT_PTR) t) { }   // The destructor performs the cleanup.   ~CEnsureCleanup() { Cleanup(); }   // Helper methods to tell if the value represents a valid object or not..   BOOL IsValid() { return(m_t != tInvalid); }   BOOL IsInvalid() { return(!IsValid()); }   // Re-assigning the object forces the current object to be cleaned-up.   TYPE operator=(TYPE t) {       Cleanup();       m_t = (UINT_PTR) t;      return(*this);     }   // Returns the value (supports both 32-bit and 64-bit Windows).   operator TYPE() {       return (TYPE) m_t;   }   // Cleanup the object if the value represents a valid object   void Cleanup() {       if (IsValid()) {         // In 64-bit Windows, all parameters are 64-bits,          // so no casting is required         pfn(m_t);         // Close the object.         m_t = tInvalid;   // We no longer represent a valid object.      }   }   private:   UINT_PTR m_t;           // The member representing the object};///////////////////////////////////////////////////////////////////////////////// Macros to make it easier to declare instances of the template // class for specific data types.#define MakeCleanupClass(className, tData, pfnCleanup) \   typedef CEnsureCleanup<tData, (PFNENSURECLEANUP) pfnCleanup> className;#define MakeCleanupClassX(className, tData, pfnCleanup, tInvalid) \   typedef CEnsureCleanup<tData, (PFNENSURECLEANUP) pfnCleanup, \   (INT_PTR) tInvalid> className;///////////////////////////////////////////////////////////////////////////////// Instances of the template C++ class for common data types.MakeCleanupClass(CEnsureCloseHandle,        HANDLE,    CloseHandle);MakeCleanupClassX(CEnsureCloseFile,         HANDLE,    CloseHandle,    INVALID_HANDLE_VALUE);MakeCleanupClass(CEnsureLocalFree,          HLOCAL,    LocalFree);MakeCleanupClass(CEnsureGlobalFree,         HGLOBAL,   GlobalFree);MakeCleanupClass(CEnsureRegCloseKey,        HKEY,      RegCloseKey);MakeCleanupClass(CEnsureCloseServiceHandle, SC_HANDLE, CloseServiceHandle);MakeCleanupClass(CEnsureCloseWindowStation, HWINSTA,   CloseWindowStation);MakeCleanupClass(CEnsureCloseDesktop,       HDESK,     CloseDesktop);MakeCleanupClass(CEnsureUnmapViewOfFile,    PVOID,     UnmapViewOfFile);MakeCleanupClass(CEnsureFreeLibrary,        HMODULE,   FreeLibrary);///////////////////////////////////////////////////////////////////////////////// Special class for releasing a reserved region.// Special class is required because VirtualFree requires 3 parametersclass CEnsureReleaseRegion {public:   CEnsureReleaseRegion(PVOID pv = NULL) : m_pv(pv) { }   ~CEnsureReleaseRegion() { Cleanup(); }   PVOID operator=(PVOID pv) {       Cleanup();       m_pv = pv;       return(m_pv);    }   operator PVOID() { return(m_pv); }   void Cleanup() {       if (m_pv != NULL) {          VirtualFree(m_pv, 0, MEM_RELEASE);          m_pv = NULL;       }    }   private:   PVOID m_pv;};///////////////////////////////////////////////////////////////////////////////// Special class for freeing a block from a heap// Special class is required because HeapFree requires 3 parametersclass CEnsureHeapFree {public:   CEnsureHeapFree(PVOID pv = NULL, HANDLE hHeap = GetProcessHeap())       : m_pv(pv), m_hHeap(hHeap) { }   ~CEnsureHeapFree() { Cleanup(); }   PVOID operator=(PVOID pv) {       Cleanup();       m_pv = pv;       return(m_pv);    }   operator PVOID() { return(m_pv); }   void Cleanup() {       if (m_pv != NULL) {          HeapFree(m_hHeap, 0, m_pv);          m_pv = NULL;       }    }   private:   HANDLE m_hHeap;   PVOID m_pv;};template <class TV, class TM>inline TV chROUNDDOWN(TV Value, TM Multiple) {   return((Value / Multiple) * Multiple);}// This inline function rounds a value down to the nearest multipletemplate <class TV, class TM>inline TV chROUNDUP(TV Value, TM Multiple) {   return(chROUNDDOWN(Value, Multiple) +       (((Value % Multiple) > 0) ? Multiple : 0));}///////////////////////////////// End of File /////////////////////////////////


 

//IoCompletionPort.h/******************************************************************************Module:  IOCP.hNotices: Copyright (c) 2007 Jeffrey Richter & Christophe NasarrePurpose: This class wraps an I/O Completion Port.         See Appendix B.******************************************************************************/#pragma once   // Include this header file once per compilation unit///////////////////////////////////////////////////////////////////////////////#include <Windows.h>#define chVERIFY#define chASSERT///////////////////////////////////////////////////////////////////////////////class CIOCP {public:   CIOCP(int nMaxConcurrency = -1) {       m_hIOCP = NULL;       if (nMaxConcurrency != -1)         (void) Create(nMaxConcurrency);   }   ~CIOCP() {       if (m_hIOCP != NULL)          chVERIFY(CloseHandle(m_hIOCP));    }   BOOL Close() {      BOOL bResult = CloseHandle(m_hIOCP);      m_hIOCP = NULL;      return(bResult);   }   BOOL Create(int nMaxConcurrency = 0) {      m_hIOCP = CreateIoCompletionPort(         INVALID_HANDLE_VALUE, NULL, 0, nMaxConcurrency);      chASSERT(m_hIOCP != NULL);      return(m_hIOCP != NULL);   }   BOOL AssociateDevice(HANDLE hDevice, ULONG_PTR CompKey) {      BOOL fOk = (CreateIoCompletionPort(hDevice, m_hIOCP, CompKey, 0)          == m_hIOCP);      chASSERT(fOk);      return(fOk);   }   BOOL AssociateSocket(SOCKET hSocket, ULONG_PTR CompKey) {      return(AssociateDevice((HANDLE) hSocket, CompKey));   }   BOOL PostStatus(ULONG_PTR CompKey, DWORD dwNumBytes = 0,       OVERLAPPED* po = NULL) {      BOOL fOk = PostQueuedCompletionStatus(m_hIOCP, dwNumBytes, CompKey, po);      chASSERT(fOk);      return(fOk);   }   BOOL GetStatus(ULONG_PTR* pCompKey, PDWORD pdwNumBytes,      OVERLAPPED** ppo, DWORD dwMilliseconds = INFINITE) {      return(GetQueuedCompletionStatus(m_hIOCP, pdwNumBytes,          pCompKey, ppo, dwMilliseconds));   }private:   HANDLE m_hIOCP;};///////////////////////////////// End of File /////////////////////////////////


 

//main.cpp/******************************************************************************Module:  FileCopy.cppNotices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre******************************************************************************/#include "IOCompletionPort.h" // See Appendix A.#include "EnsureCleanup.h"    // See Appendix A.#include <WindowsX.h>// C RunTime Header Files#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <tchar.h>#include <string>///////////////////////////////////////////////////////////////////////////////// Each I/O Request needs an OVERLAPPED structure and a data bufferclass CIOReq : public OVERLAPPED {public:   CIOReq() {      Internal = InternalHigh = 0;         Offset = OffsetHigh = 0;         hEvent = NULL;      m_nBuffSize = 0;      m_pvData = NULL;   }   ~CIOReq() {      if (m_pvData != NULL)         VirtualFree(m_pvData, 0, MEM_RELEASE);   }   BOOL AllocBuffer(SIZE_T nBuffSize) {      m_nBuffSize = nBuffSize;      m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_COMMIT, PAGE_READWRITE);      return(m_pvData != NULL);   }   BOOL Read(HANDLE hDevice, PLARGE_INTEGER pliOffset = NULL) {      if (pliOffset != NULL) {         Offset     = pliOffset->LowPart;         OffsetHigh = pliOffset->HighPart;      }      return(::ReadFile(hDevice, m_pvData, m_nBuffSize, NULL, this));   }   BOOL Write(HANDLE hDevice, PLARGE_INTEGER pliOffset = NULL) {      if (pliOffset != NULL) {         Offset     = pliOffset->LowPart;         OffsetHigh = pliOffset->HighPart;      }      return(::WriteFile(hDevice, m_pvData, m_nBuffSize, NULL, this));   }private:   SIZE_T m_nBuffSize;   PVOID  m_pvData;};/////////////////////////////////////////////////////////////////////////////////#define BUFFSIZE              (64 * 1024) // The size of an I/O bufferDWORD BUFFSIZE = 0;#define MAX_PENDING_IO_REQS   4           // The maximum # of I/Os// The completion key values indicate the type of completed I/O.#define CK_READ  1#define CK_WRITE 2///////////////////////////////////////////////////////////////////////////////BOOL FileCopy(PCTSTR pszFileSrc, PCTSTR pszFileDst) {   BOOL bOk = FALSE;    // Assume file copy fails   LARGE_INTEGER liFileSizeSrc = { 0 }, liFileSizeDst;   try {      {      // Open the source file without buffering & get its size      CEnsureCloseFile hFileSrc = CreateFile(pszFileSrc, GENERIC_READ,          FILE_SHARE_READ, NULL, OPEN_EXISTING,          FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL);      if (hFileSrc.IsInvalid()) goto leave;      // Get the file's size      GetFileSizeEx(hFileSrc, &liFileSizeSrc);      // Nonbuffered I/O requires sector-sized transfers.      // I'll use buffer-size transfers since it's easier to calculate.      liFileSizeDst.QuadPart = chROUNDUP(liFileSizeSrc.QuadPart, BUFFSIZE);      // Open the destination file without buffering & set its size      CEnsureCloseFile hFileDst = CreateFile(pszFileDst, GENERIC_WRITE,          0, NULL, CREATE_ALWAYS,          FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, hFileSrc);      if (hFileDst.IsInvalid()) goto leave;      // File systems extend files synchronously. Extend the destination file       // now so that I/Os execute asynchronously improving performance.      SetFilePointerEx(hFileDst, liFileSizeDst, NULL, FILE_BEGIN);      SetEndOfFile(hFileDst);      // Create an I/O completion port and associate the files with it.      CIOCP iocp(2);//并行数      iocp.AssociateDevice(hFileSrc, CK_READ);  // Read from source file      iocp.AssociateDevice(hFileDst, CK_WRITE); // Write to destination file      // Initialize record-keeping variables      CIOReq ior[MAX_PENDING_IO_REQS];      LARGE_INTEGER liNextReadOffset = { 0 };      int nReadsInProgress  = 0;      int nWritesInProgress = 0;      // Prime the file copy engine by simulating that writes have completed.      // This causes read operations to be issued.      for (int nIOReq = 0; nIOReq < _countof(ior); nIOReq++) {         // Each I/O request requires a data buffer for transfers         chVERIFY(ior[nIOReq].AllocBuffer(BUFFSIZE));         nWritesInProgress++;         iocp.PostStatus(CK_WRITE, 0, &ior[nIOReq]);      }      BOOL bResult = FALSE;            // Loop while outstanding I/O requests still exist      while ((nReadsInProgress > 0) || (nWritesInProgress > 0)) {         // Suspend the thread until an I/O completes         ULONG_PTR CompletionKey;         DWORD dwNumBytes;         CIOReq* pior;         bResult = iocp.GetStatus(&CompletionKey, &dwNumBytes, (OVERLAPPED**) &pior, INFINITE);         switch (CompletionKey) {         case CK_READ:  // Read completed, write to destination            nReadsInProgress--;            bResult = pior->Write(hFileDst);  // Write to same offset read from source            nWritesInProgress++;            break;         case CK_WRITE: // Write completed, read from source            nWritesInProgress--;            if (liNextReadOffset.QuadPart < liFileSizeDst.QuadPart) {               // Not EOF, read the next block of data from the source file.               bResult = pior->Read(hFileSrc, &liNextReadOffset);               nReadsInProgress++;               liNextReadOffset.QuadPart += BUFFSIZE; // Advance source offset            }            break;         }      }      bOk = TRUE;      }   leave:;   }   catch (...) {   }   if (bOk) {      // The destination file size is a multiple of the page size. Open the      // file WITH buffering to shrink its size to the source file's size.      CEnsureCloseFile hFileDst = CreateFile(pszFileDst, GENERIC_WRITE,          0, NULL, OPEN_EXISTING, 0, NULL);      if (hFileDst.IsValid()) {                  SetFilePointerEx(hFileDst, liFileSizeSrc, NULL, FILE_BEGIN);         SetEndOfFile(hFileDst);      }   }   return(bOk);}int wmain(int argc,wchar_t **argv) {GetDiskFreeSpaceW(NULL,NULL,&BUFFSIZE,NULL,NULL); //cache bytes of per sector for support FILE_FLAG_NO_BUFFERING flag.if(argc < 3)return -1;FileCopy(argv[1],argv[2]);return(0);}//////////////////////////////// End of File //////////////////////////////////


 

0 0
原创粉丝点击