最近在看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 called
LARGE_INTEGER liPerfNow;
QueryPerformanceCounter(&liPerfNow);
return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)
/ m_liPerfFreq.QuadPart);
}
__int64 NowInMicro() const { // Return # of microseconds
// since Start was called
LARGE_INTEGER liPerfNow;
QueryPerformanceCounter(&liPerfNow);
return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000000)
/ m_liPerfFreq.QuadPart);
}
private:
LARGE_INTEGER m_liPerfFreq; // Counts per second
LARGE_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 slot
unsigned 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 view
DWORD dwBytesInBlo