#include <stdio.h>
#include <windows.h>
#define MAX_THREADS 16
#define BUFFER_SIZE (32*1024) // 32KB
#define KEY_FILE 0x00000001
#define KEY_START 0x00000002
#define KEY_EXIT 0x00000003
typedef struct _CHUNK
{
OVERLAPPED overlapped;
LPVOID buffer;
}
CHUNK, *PCHUNK;
HANDLE g_hSourceFile = NULL;
HANDLE g_hIOCompletionPort = NULL;
ULARGE_INTEGER g_uiReadPointer = {0};
int g_iResult = 0;
DWORD WINAPI IOCP_WorkThread(LPVOID lpParam);
int main(int argc, char** argv)
{
HANDLE hThread[MAX_THREADS] = {NULL};
SYSTEM_INFO systemInfo = {0};
ULARGE_INTEGER fileSize = {0};
OVERLAPPED StartOverlapped = {0};
OVERLAPPED ExitOverlapped = {0};
DWORD dwExitStatus = ERROR_SUCCESS;
DWORD dwStatus = 0;
DWORD dwNumProcessors = 2;
UINT i = 0;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <source file>\n", argv[0]);
dwExitStatus = ERROR_INVALID_PARAMETER;
goto EXIT;
}
GetSystemInfo(&systemInfo);
dwNumProcessors = systemInfo.dwNumberOfProcessors;
g_hSourceFile = CreateFile(
argv[1],
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
NULL
);
if (g_hSourceFile == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "%s: Failed to open %s, error %d\n",
argv[0],
argv[1],
dwExitStatus = GetLastError());
goto EXIT;
}
fileSize.LowPart = GetFileSize(g_hSourceFile, &fileSize.HighPart);
if ((fileSize.LowPart == 0xffffffff) && (GetLastError() != NO_ERROR))
{
fprintf(stderr, "%s: GetFileSize failed, error %d\n",
argv[0],
dwExitStatus = GetLastError());
goto EXIT;
}
g_hIOCompletionPort = CreateIoCompletionPort(
g_hSourceFile,
NULL,
KEY_FILE,
dwNumProcessors
);
if (g_hIOCompletionPort == NULL)
{
fprintf(stderr,
"%s: Failed to create IO completion port (error %d)\n",
argv[0],
dwExitStatus = GetLastError());
goto EXIT;
}
for ( i = 0; i < 2*dwNumProcessors; ++i )
{
hThread[i] = CreateThread(
NULL, 0,
(LPTHREAD_START_ROUTINE)IOCP_WorkThread,
(LPVOID)&fileSize,
0, NULL
);
if (hThread[i] == NULL)
{
fprintf(stderr, "%s: Failed to create thread #%d (error %d)\n",
argv[0], i, dwExitStatus = GetLastError());
goto EXIT;
}
}
PostQueuedCompletionStatus(
g_hIOCompletionPort,
0,
KEY_START,
&StartOverlapped
);
dwStatus = WaitForMultipleObjects(
2*dwNumProcessors,
hThread,
FALSE,
INFINITE
);
if (dwStatus == WAIT_FAILED)
{
fprintf(stderr, "%s: Wait failed (error %d)\n",
argv[0], dwExitStatus = GetLastError());
goto EXIT;
}
for ( i = 0; i < 2*dwNumProcessors - 1; ++i )
{
PostQueuedCompletionStatus(
g_hIOCompletionPort,
0,
KEY_EXIT,
&ExitOverlapped
);
}
dwStatus = WaitForMultipleObjects(
2*dwNumProcessors,
hThread,
TRUE,
INFINITE
);
if (dwStatus == WAIT_FAILED)
{
fprintf(stderr, "%s: Wait failed (error %d)\n",
argv[0], dwExitStatus = GetLastError());
goto EXIT;
}
fprintf(stderr, "result = [%d].\n", g_iResult);
EXIT:
for ( i = 0; i < 2*dwNumProcessors; ++i )
{
if (hThread[i])
{
CloseHandle(hThread[i]);
hThread[i] = NULL;
}
}
if (g_hIOCompletionPort)
{
CloseHandle(g_hIOCompletionPort);
g_hIOCompletionPort = NULL;
}
if (g_hSourceFile)
{
CloseHandle(g_hSourceFile);
g_hSourceFile = NULL;
}
return dwExitStatus;
}
DWORD WINAPI IOCP_WorkThread(LPVOID lpParam)
{
DWORD i = 0;
DWORD dwKey = 0;
DWORD dwNumBytes = 0;
LPOVERLAPPED completedOverlapped = NULL;
CHUNK chunk = {0};
while (true)
{
BOOL bSuccess = GetQueuedCompletionStatus(
g_hIOCompletionPort,
&dwNumBytes,
&dwKey,
&completedOverlapped,
INFINITE
);
if (!bSuccess)
{
fprintf(stderr, "GetQueuedCompletionStatus removed a bad I/O packet (error %d)\n", GetLastError());
ExitThread(E_FAIL);
}
if (completedOverlapped == NULL)
{
fprintf(stderr, "GetQueuedCompletionStatus failed (error %d)\n", GetLastError());
ExitThread(E_FAIL);
}
if (dwKey == KEY_EXIT)
{
ExitThread(ERROR_SUCCESS);
}
if (dwKey == KEY_FILE)
{
PCHUNK completedChunk = (PCHUNK)completedOverlapped;
PBYTE pbData = (PBYTE)completedChunk->buffer;
for ( i = 0; i < dwNumBytes; ++i )
{
if ( pbData[i] == 0xff )
{
g_iResult++;
}
}
VirtualFree((LPVOID)pbData, 0, MEM_RELEASE);
}
if (dwKey == KEY_FILE || dwKey == KEY_START)
{
BOOL bMoreToRead = FALSE;
if (g_uiReadPointer.QuadPart < ((ULARGE_INTEGER*)lpParam)->QuadPart)
{
bMoreToRead = TRUE;
chunk.overlapped.Offset = g_uiReadPointer.LowPart;
chunk.overlapped.OffsetHigh = g_uiReadPointer.HighPart;
chunk.overlapped.hEvent = NULL;
g_uiReadPointer.QuadPart += BUFFER_SIZE;
}
if (bMoreToRead)
{
chunk.buffer = VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (chunk.buffer == NULL)
{
fprintf(stderr, "VirtualAlloc failed (error %d)\n", GetLastError());
ExitThread(E_OUTOFMEMORY);
}
DWORD dwNumBytesTmp = 0;
DWORD dwSuccess = ReadFile(
g_hSourceFile,
chunk.buffer,
BUFFER_SIZE,
&dwNumBytesTmp,
&chunk.overlapped
);
if (!dwSuccess && (GetLastError() == ERROR_HANDLE_EOF))
{
fprintf(stderr, "End of file\n");
VirtualFree((LPVOID)chunk.buffer, 0, MEM_RELEASE);
ExitThread(E_FAIL);
}
if (!dwSuccess && (GetLastError() != ERROR_IO_PENDING))
{
fprintf(stderr, "ReadFile at [%lx:%lx] failed (error %d)\n",
chunk.overlapped.OffsetHigh,
chunk.overlapped.Offset,
GetLastError());
VirtualFree((LPVOID)chunk.buffer, 0, MEM_RELEASE);
ExitThread(E_FAIL);
}
}
else
{
ExitThread(ERROR_SUCCESS);
}
}
}
ExitThread(E_FAIL);
}
一个IOCP的小例子
最新推荐文章于 2024-02-18 21:19:30 发布