IOCP 檔案拷貝
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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- IO流-檔案拷貝
- 檔案內容拷貝
- Golang命令列拷貝檔案Golang命令列
- asm拷貝檔案到檔案系統ASM
- [java IO流]之檔案拷貝Java
- c語言拷貝檔案程式C語言
- Python基礎 - 檔案拷貝Python
- 二進位制檔案拷貝
- 檔案操作(二進位制拷貝)
- 使用expect指令碼SCP拷貝檔案指令碼
- linux 帶路徑拷貝檔案Linux
- linux採用scp命令拷貝檔案到本地,拷貝本地檔案到遠端伺服器Linux伺服器
- 資料檔案拷貝檔案頭驗證錯誤
- Java IO 流之拷貝(複製)檔案Java
- linux parallel rsync 拷貝N多檔案LinuxParallel
- 零拷貝讀取檔案成 Go 物件Go物件
- 使用UltraEdit 拷貝二進位制檔案
- Java實現檔案拷貝的4種方法.Java
- 11g中節點間拷貝檔案
- 【ASM學習】從ASM拷貝檔案的方法ASM
- vue深拷貝淺拷貝Vue
- python 指標拷貝,淺拷貝和深拷貝Python指標
- 一文搞懂Java引用拷貝、淺拷貝、深拷貝Java
- jquery之物件拷貝深拷貝淺拷貝案例講解jQuery物件
- C++拷貝建構函式(深拷貝,淺拷貝)C++函式
- iOS深拷貝和淺拷貝iOS
- JS深拷貝與淺拷貝JS
- Java深拷貝和淺拷貝Java
- 物件深拷貝和淺拷貝物件
- javascript 淺拷貝VS深拷貝JavaScript
- JavaScript 深度拷貝和淺拷貝JavaScript
- JavaScript深拷貝和淺拷貝JavaScript
- js 淺拷貝和深拷貝JS
- js 深拷貝和淺拷貝JS
- JavaScript淺拷貝和深拷貝JavaScript
- js深拷貝和淺拷貝JS
- js 深拷貝 vs 淺拷貝JS
- 跨網路拷貝檔案的簡單實踐