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.h
Notices: Copyright (c) 2007 Jeffrey Richter & Christophe Nasarre
Purpose: 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 parameters
class 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 parameters
class 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 multiple
template <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.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 <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.cpp
Notices: 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 buffer
class 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 buffer
DWORD 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 //