IOCP 檔案拷貝

licup123發表於2009-08-20

IOCP類

/******************************************************************************
Module:  IOCP.h
Notices: Copyright (c) 2007 Jeffrey Richter & Christophe Nasarre
Purpose: This class wraps an I/O Completion Port.
         See Appendix B.
******************************************************************************/


#pragma once   // Include this header file once per compilation unit


///////////////////////////////////////////////////////////////////////////////


#include "..\CommonFiles\CmnHdr.h"              // See Appendix A.


///////////////////////////////////////////////////////////////////////////////


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);
      /*
   PostQueuedCompletionStatus函式,向每個工作者執行緒都傳送—個特殊的完成資料包。
   該函式會指示每個執行緒都“立即結束並退出”.下面是PostQueuedCompletionStatus函式的定義:
      BOOL PostQueuedCompletionStatus(
      HANDLE CompletlonPort,
      DW0RD  dwNumberOfBytesTrlansferred,
      DWORD  dwCompletlonKey,
      LPOVERLAPPED lpoverlapped,
      );

   其中,CompletionPort引數指定想向其傳送一個完成資料包的完成埠物件。
   而就dwNumberOfBytesTransferred,dwCompletionKey和lpOverlapped這三個引數來說.
   每—個都允許我們指定—個值,直接傳遞給GetQueuedCompletionStatus函式中對應的引數。
   這樣—來。—個工作者執行緒收到傳遞過來的三個GetQueuedCompletionStatus函式引數後,
   便可根據由這三個引數的某一個設定的特殊值,決定何時應該退出。
   例如,可用dwCompletionPort引數傳遞0值,而—個工作者執行緒會將其解釋成中止指令。
   一旦所有工作者執行緒都已關閉,便可使用CloseHandle函式,關閉完成埠。最終安全退出程式。
      PostQueuedCompletionStatus函式提供了一種方式來與執行緒池中的所有執行緒進行通訊。如,當使用者終止服務應用程式時,
      我們想要所有執行緒都完全利索地退出。但是如果各執行緒還在等待完成埠而又沒有已完成的I/O 請求,那麼它們將無法被喚醒。
      通過為執行緒池中的每個執行緒都呼叫一次PostQueuedCompletionStatus,我們可以將它們都喚醒。
      每個執行緒會對GetQueuedCompletionStatus的返回值進行檢查,如果發現應用程式正在終止,那麼它們就可以進行清理工作並正常地退出。 

 

  PostQueuedCompletionStatus主要是投遞一個任務到完成佇列當中,
   從而使得在等待佇列訊息的某一個執行緒收取到.其參與分別與GetQueuedCompletionStauts相對應,
   從而可以很方便地為在等待完成訊息的執行緒(池)分派任務,而不需要另外再開執行緒資源.基於這一種特性,
   還可以把完成埠當成一個高效的佇列+執行緒池.正如1樓說的,如果你是想退出執行緒的話,
   也可以通過這種方式投遞特定的訊息.由於退出訊息一個執行緒只會處理一個(這個邏輯問題應該不用解釋),
   所以如果想讓所有業務執行緒退出,就只需要根據執行緒數量投遞多個退出訊息即可.

   */
   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 /////////////////////////////////
IOReq 類

class CIOReq : public OVERLAPPED {
public:
   CIOReq() {
      Internal = InternalHigh = 0;  
      ffset = ffsetHigh = 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;
         ffsetHigh = 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;
         ffsetHigh = pliOffset->HighPart;
      }
      return(::WriteFile(hDevice, m_pvData, m_nBuffSize, NULL, this));
   }

private:
   SIZE_T m_nBuffSize;
   PVOID  m_pvData;
};

檔案拷貝實現函式

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(0);
      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]);            //向原始檔傳送IO請求,建立IO完成佇列
      }

      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;                               //IO 完成鍵
         DWORD dwNumBytes;                                      //傳輸的資料的大小
         CIOReq* pior;
         bResult = iocp.GetStatus(&CompletionKey, &dwNumBytes, (OVERLAPPED**) &pior, INFINITE);
                                                          //當IO完成埠中有IO完成請求時就喚醒呼叫執行緒

         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);
}

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10697500/viewspace-612740/,如需轉載,請註明出處,否則將追究法律責任。

相關文章