16,472
社区成员
发帖
与我相关
我的任务
分享
#pragma once
#include <Windows.h>
#include <vector>
#include <assert.h>
using namespace std;
#define IO完成端口_退出线程 -1
class IO完成端口
{
// 声明友元函数
friend IO完成端口* 创建IO完成端口实例( DWORD 工作线程数 = 0 );
friend VOID 销毁IO完成端口实例( IO完成端口 *IO完成端口实例 );
private:
protected:
IO完成端口();
~IO完成端口();
static DWORD 工作线程( IO完成端口 *IO完成端口实例 );
HANDLE 私有_IO完成端口对象句柄;
vector<HANDLE> 私有_工作线程句柄表;
public:
typedef VOID (*回调函数)(
DWORD 错误号,
DWORD IO完成字节数,
LPOVERLAPPED 重叠IO结构
);
BOOL 绑定IO对象(
HANDLE IO对象句柄,
回调函数 完成事件处理函数,
DWORD 并发线程数 = 0
);
};
// 创建类实例
IO完成端口* 创建IO完成端口实例( DWORD 工作线程数 )
{
// 创建类实例
IO完成端口 *IO完成端口实例 = new IO完成端口;
if ( IO完成端口实例 == NULL )
return NULL;
// 创建 IO完成端口对象
IO完成端口实例->私有_IO完成端口对象句柄 = CreateIoCompletionPort( (HANDLE)-1, NULL, NULL, 0 );
if ( IO完成端口实例->私有_IO完成端口对象句柄 == NULL )
{
delete IO完成端口实例;
return NULL;
}
// 确定工作线程数
if ( 工作线程数 == 0 )
{
SYSTEM_INFO SysInf;
GetSystemInfo( &SysInf );
工作线程数 = SysInf.dwNumberOfProcessors * 2;
if ( 工作线程数 == 0 )
工作线程数 = 2;
}
// 创建工作线程
for ( DWORD i = 0; i < 工作线程数; i++ )
{
HANDLE 线程句柄 = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)IO完成端口实例->工作线程, IO完成端口实例, 0, NULL );
if ( 线程句柄 != NULL )
IO完成端口实例->私有_工作线程句柄表.push_back( 线程句柄 );
}
// 创建工作线程失败
if ( IO完成端口实例->私有_工作线程句柄表.size() == 0 )
{
CloseHandle( IO完成端口实例->私有_IO完成端口对象句柄 );
delete IO完成端口实例;
return NULL;
}
return IO完成端口实例;
}
// 销毁类实例
VOID 销毁IO完成端口实例( IO完成端口 *IO完成端口实例 )
{
assert( IO完成端口实例 );
DWORD 线程数 = IO完成端口实例->私有_工作线程句柄表.size();
// 向所有工作线程投递退出通知
for ( DWORD i = 0; i < 线程数; i++ )
PostQueuedCompletionStatus( IO完成端口实例->私有_IO完成端口对象句柄, 0, IO完成端口_退出线程, NULL );
// 等待所有工作线程退出
for ( DWORD i = 0; i < 线程数; i++ )
{
HANDLE 线程句柄 = IO完成端口实例->私有_工作线程句柄表[i];
// 等待退出, 如果超时则强制关闭
if ( WaitForSingleObject( 线程句柄 , 5000 ) == WAIT_TIMEOUT )
TerminateThread( 线程句柄, IO完成端口_退出线程 );
CloseHandle( 线程句柄 );
}
// 清空句柄表
IO完成端口实例->私有_工作线程句柄表.clear();
// 关闭IO完成端口对象句柄
CloseHandle( IO完成端口实例->私有_IO完成端口对象句柄 );
// 删除IO完成端口实例
delete IO完成端口实例;
}
// 构造函数
IO完成端口::IO完成端口()
:私有_IO完成端口对象句柄( NULL )
{
}
// 析构函数
IO完成端口::~IO完成端口()
{
}
// IO对象与IO完成端口绑定
BOOL IO完成端口::绑定IO对象(
HANDLE IO对象句柄,
回调函数 完成事件处理函数,
DWORD 并发线程数
)
{
assert( 完成事件处理函数 );
return ( NULL != CreateIoCompletionPort(IO对象句柄, 私有_IO完成端口对象句柄, (ULONG_PTR)完成事件处理函数, 并发线程数) );
}
// 工作者线程, 负责 等待完成事件, 回调处理函数
DWORD IO完成端口::工作线程( IO完成端口 *IO完成端口实例 )
{
HANDLE IO完成端口对象句柄 = IO完成端口实例->私有_IO完成端口对象句柄;
DWORD IO完成字节数 = 0;
ULONG_PTR 用户参数 = NULL;
LPOVERLAPPED 重叠IO结构 = NULL;
DWORD 错误号 = 0;
// GetQueuedCompletionStatus 循环
GQCS循环:
{
// 等待 IO完成事件
if ( FALSE != GetQueuedCompletionStatus(IO完成端口对象句柄, &IO完成字节数, &用户参数, &重叠IO结构, INFINITE) )
{
// 退出线程
if ( 用户参数 == IO完成端口_退出线程 )
return IO完成端口_退出线程;
错误号 = 0;
}
else
{
错误号 = GetLastError();
switch ( 错误号 )
{
case ERROR_INVALID_HANDLE:
{
return ERROR_INVALID_HANDLE;
}
case ERROR_ABANDONED_WAIT_0:
{
return ERROR_ABANDONED_WAIT_0;
}
}
}
if ( 用户参数 != NULL )
// 回调用户提供的事件处理函数
((回调函数)用户参数)( 错误号, IO完成字节数, 重叠IO结构 );
} goto GQCS循环;
}
#include "stdafx.h"
#include "IO完成端口.hpp"
#include <assert.h>
struct MYOVERLAPPED
{
OVERLAPPED OverLapped;
HANDLE hFile;
DWORD dwBufLen;
BYTE *lpBuffer;
};
VOID IO完成事件处理函数(
DWORD 错误号,
DWORD IO完成字节数,
LPOVERLAPPED 重叠IO结构
)
{
printf( "IO完成事件处理函数: 错误 %d, IO完成字节数 %d, 重叠IO结构 %d .\n", 错误号, IO完成字节数, 重叠IO结构 );
// 继续读
MYOVERLAPPED *myol = (MYOVERLAPPED *)重叠IO结构;
SetFilePointer( myol->hFile, IO完成字节数, 0, FILE_CURRENT );
ReadFile( myol->hFile, myol->lpBuffer, myol->dwBufLen, NULL, 重叠IO结构 );
}
int _tmain(int argc, _TCHAR* argv[])
{
IO完成端口 *IO完成端口实例 = 创建IO完成端口实例();
assert( IO完成端口实例 );
HANDLE hFile = CreateFile( TEXT("F:\\Fraps\\Movies\\fsx 2011-07-01 13-48-21-66.avi"),
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
// 文件对象与IO完成端口关联
IO完成端口实例->绑定IO对象( hFile, IO完成事件处理函数 );
MYOVERLAPPED *myol = new MYOVERLAPPED;
memset( myol, 0, sizeof(MYOVERLAPPED) );
myol->hFile = hFile;
myol->dwBufLen = 4096;
myol->lpBuffer = new BYTE[myol->dwBufLen];
// 异步读文件
if ( FALSE == ReadFile( hFile, myol->lpBuffer, myol->dwBufLen, NULL, (LPOVERLAPPED)myol ) )
assert( GetLastError() == ERROR_IO_PENDING );
getchar();
销毁IO完成端口实例( IO完成端口实例 );
delete[] myol->lpBuffer;
delete myol;
CloseHandle( hFile );
return 0;
}