最近在看Windows核心编程17章
作者推崇使用FileMapping来进行大文件读写。虽然这样可以直接把文件映射到进程地址空间,由操作系统来进行后备的换成,换页等复杂操作。程序员只需要直接把文件当做内存地址来操作即可。
可是笔者发现这可能对于编码来说相对简单了,可是把缓存这些全交给操作系统来处理并不是一个好的方法。尤其在处理大文件IO的时候。于是笔者对原书上的一个例子进行了改写对比。首先这是改写后的代码。此代码当然也支持原书本上的逻辑。
完整代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>//
class CStopwatch {
public:CStopwatch() { QueryPerformanceFrequency(&m_liPerfFreq); Start(); }void Start() { QueryPerformanceCounter(&m_liPerfStart); }__int64 Now() const { // Returns # of millisecond since Start was calledLARGE_INTEGER liPerfNow;QueryPerformanceCounter(&liPerfNow);return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)/ m_liPerfFreq.QuadPart);}__int64 NowInMicro() const { // Return # of microseconds// since Start was calledLARGE_INTEGER liPerfNow;QueryPerformanceCounter(&liPerfNow);return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000000)/ m_liPerfFreq.QuadPart);}private:LARGE_INTEGER m_liPerfFreq; // Counts per secondLARGE_INTEGER m_liPerfStart; // Starting count
};CStopwatch stopwatch;
//typedef struct {PVOID pvAddr;DWORD dwBlockSize;DWORD dwCount;bool bIsFinished;
} WORK_DATA, *PWORK_DATA;typedef struct {WORK_DATA wDATA;PTP_WORK pWork;
} WORKITEM_INFO, *PWORKITEM_INFO;#define MAX_THREADS 4
PWORKITEM_INFO g_WORKITEM[MAX_THREADS] = { 0 };
PBYTE g_BUFF[MAX_THREADS] = { 0 };HANDLE hSemp = NULL;
//VOID CALLBACK WorkCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WORK Work) {PWORK_DATA pData = (PWORK_DATA)Context;// Count the number of 0s in this block.PBYTE pFile = (PBYTE)pData->pvAddr;for (DWORD dwByte = 0; dwByte < pData->dwBlockSize; dwByte++) {if (pFile[dwByte] == 0)pData->dwCount++;}pData->bIsFinished = true;ReleaseSemaphoreWhenCallbackReturns(Instance, hSemp, 1);
}__int64 CountWithFileMapMultiThreads(HANDLE hFileMap, __int64 qwFileSize, DWORD dwBlockSize, DWORD nThreads) {if (nThreads > MAX_THREADS)return -1; // invalid threads count.ZeroMemory(g_WORKITEM, sizeof(PTP_WORK) * nThreads);__int64 qwFileOffset = 0, qwNumOfZeros = 0;hSemp = CreateSemaphore(NULL, nThreads, nThreads, NULL);// allocate the buff.for (unsigned int i = 0; i < nThreads; i++) {g_WORKITEM[i] = (PWORKITEM_INFO)malloc(sizeof(WORKITEM_INFO));g_WORKITEM[i]->wDATA.bIsFinished = true;g_WORKITEM[i]->pWork = NULL;g_WORKITEM[i]->wDATA.pvAddr = NULL;}while (qwFileSize > 0) {WaitForSingleObject(hSemp, INFINITE); // wait for a resource.// do some resource clean up.for (unsigned int i = 0; i < nThreads; i++) {if (g_WORKITEM[i]) { // there is a working item.if (g_WORKITEM[i]->wDATA.bIsFinished && g_WORKITEM[i]->pWork) { // this item has been finished// get the data.qwNumOfZeros += g_WORKITEM[i]->wDATA.dwCount;// Unmap the file.UnmapViewOfFile(g_WORKITEM[i]->wDATA.pvAddr);// close the work item.CloseThreadpoolWork(g_WORKITEM[i]->pWork);g_WORKITEM[i]->pWork = NULL;}}}// get a free slotunsigned int nSlotID;for (nSlotID = 0; nSlotID < nThreads; nSlotID++) {if (g_WORKITEM[nSlotID]->pWork == NULL) // get a free slot.break;}// there is a thread available.if (nSlotID < nThreads){// Determine the number of bytes to be mapped in this viewDWORD dwBytesInBlo