完成端口读取文件

版权声明: https://blog.csdn.net/dashoumeixi/article/details/83587590

完成端口首先得了解什么是重叠io OVERLAPPED I/O 异步APC

下面的例子只告诉你怎么写这个程序, 不是告诉你理论,即如果在服务器上为什么不使用一个线程一个客户的模型

CreateIoCompletionPort  创建一个完成端口. 这个函数有一般需要调用2次

     第一次:HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 线程数量);

            如此创建了一个完成端口; 这个完成端口可以与其他有OVERLAPPED属性的HANDLE 关联

    第二次: CreateIoCompletionPort(hFile, iocp,(DWORD)key, 0); 

            把第一个参数的 handle 与 完成端口 iocp 绑定在一起, 第三个参数自定义数据

            需要注意 第一个参数的handle 必须是一个可重叠的 , 即创建handle时有 OVERLAPPED 属性的.

GetQueuedCompletionStatus  一般是在线程中调用, 用于返回结果, 就好像 GetOverlappedResult 一样.

  注:一般在线程中调用的意思是 , 完成端口一般将创建一组线程池来处理获取的结果

当在线程中调用了 GetQueuedCompletionStatus (iocp , ....)  之后 , 此线程相当于已归属于 对应的iocp(完成端口了).

意思是,此线程将监听完成端口的情况,一旦任务完成就会返回

PostQueuedCompletionStatus: 模拟已经完成的请求. 换句话说,你可以把这个函数理解成一个想要结束线程的函数;

typedef struct
{
	HANDLE hFile;
} cp_key;                  //一个自定义数据 ,随便填吧

typedef struct 
{
	OVERLAPPED overlap;
	char buf[1024];
} cp_overlapped;        //overlapped 放第一个, 相当于一个OVERLAPPED结构


unsigned int __stdcall io_thread(void *param)
{
	HANDLE iocp = (HANDLE)param;
	_tprintf(TEXT("线程创建完毕 iocp:%p\n"), iocp);
	DWORD bytesRead = 0;
	cp_key * key = 0;
	cp_overlapped * s = 0;
	DWORD ret = 0;

	while (1)
	{
        
        //等待完成端口的响应
		ret = GetQueuedCompletionStatus(iocp, &bytesRead, (LPDWORD)&key, (LPOVERLAPPED*)&s, INFINITE);

        //退出线程
		if (key == 0 && s == 0){
			_tprintf(TEXT("exit"));
			break;
		}
		_tprintf(TEXT("byteread:%d, key:%p,ret :%d\n"), bytesRead, key->hFile, ret);
		_tprintf(TEXT("overlapped  offset:%d\n"), s->overlap.Offset);
		_tprintf(TEXT("%s\n"),s->buf);
	}
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	_tsetlocale(LC_CTYPE, TEXT(""));
	SYSTEM_INFO sysInfo;
	GetSystemInfo(&sysInfo);

    //准备线程数量
	const int NThread = sysInfo.dwNumberOfProcessors + 2;

    //创建一个完成端口
	HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, NThread);
	HANDLE * thread_handles = new HANDLE[NThread];

    //创建线程
	for (int i = 0; i < NThread; ++i)
		thread_handles[i] = (HANDLE)_beginthreadex(0, 0, io_thread, (void*)iocp, 0, 0);

	HANDLE hFile = CreateFile(
		TEXT("D:/download/bookmarks.html"),  //这里自己修改                                       
		GENERIC_READ,                                  
		FILE_SHARE_READ,                              
		NULL,                                         
		OPEN_EXISTING,                                
		FILE_FLAG_OVERLAPPED ,  //注意.
		NULL                                          
		);
	DWORD numread = 0 , ret = 0;
	
    //初始化数据 , 这些数据将在完成后被传递到线程中
	cp_overlapped * s = new cp_overlapped; 
	s->overlap.hEvent = NULL;
	s->overlap.Offset = 0;
	s->overlap.OffsetHigh = 0;
    
    //初始化数据 , 这些数据将在完成后被传递到线程中
	cp_key * key = new cp_key;
	key->hFile = hFile;

    //将文件handle 与 完成端口 关联在一起 , 注意 key 的类型转换
	CreateIoCompletionPort(hFile, iocp,(DWORD)key, 0);
    
    //读取文件 , 等读完后, 将有一个线程处理读完后的步骤
    //注意 cp_overlapped 的使用, 在读完后, 其中一个线程将获取此数据
	ret = ReadFile(hFile, s->buf, 1024, &numread,&s->overlap);
	printf("readfile ret:%d , ERR:%d\n", ret, GetLastError());
	

    //等待一下
	for (int i = 0; i < 2; ++i)
		Sleep(1000);

    //告诉所有线程去死吧
	for (int i = 0; i < NThread; ++i)
		PostQueuedCompletionStatus(iocp, 0, (DWORD)0, 0);
    
	WaitForMultipleObjects(NThread, thread_handles, TRUE, -1);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/dashoumeixi/article/details/83587590