轻松讲解完成端口模型

 

现在,快递业务是越来越多,越来越常见了。发快递,有发送端和接收端,

接收快递这端大概是这么一个流程:有一个仓库,接收来自各个公司邮寄的快递,

然后这个快递的派送员,一直等着仓库里有快递,只有有一件快递,则就会有一个

仓库快递员去把这件快递送到客户手里。

上面的流程,大概就是完成端口模型的流程了。让我细细道来。

有一个老板,相当于程序里的主线程;

老板盖了一间厂房,相当于程序里创建完成端口CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,4),

最后一个参数是4,为什么是4呢,因为仓库只有4辆送货电动车,所以同时只有四个人派送快递到客户手里。

现在,得有快递公司把快递寄到我这里,才有活干啊。就得与快递公司签约,快递公司就相当于程序里的文件句柄(

也可以是套接字,油槽之类的东东),只要和这些快递公司相关的快递都会送到我这个仓库里

(只要和绑定的文件相关的操作完成情况都会送到完成端口),签约的过程就相当于,把文件句柄和完成端口绑定过程,CreateIoCompletionPort(hFile,hComPort,0,0))(第二次调用)第三个参数相对于快递公司的信息,

你如 0 代表顺丰,1代表圆通,当你收到快递后,你看到0,你就知道,顺丰送过来的。

好了,现在有快递过来了,你得派人去派发这些快递啊。老板需要招几个员工,那招几个呢?好吧,公司只有

4辆送货电动车,招一个人,三辆车闲着,招十个人,六个人闲着,还得发工资。那就四个吧,一人一辆车。

算了,还是招五个人吧,万一有一个人生病了呢。招五个人就相当于我们创建五个工作线程,

4辆车,就相当于我们电脑有四个CPU。

好了,现在要做的就是,让这五个人当中四个有电动车的人,去仓库等着,有一个快递到仓库,就去派发这件快递,

就相当于,程序里面线程里的的GetQueuedCompletionStatus(pServerInfo->hCompletionPort,

&dwNumberOfBytesTransferred,   (PULONG_PTR)&ulCompletionKey,(LPOVERLAPPED*)&lpOverlapped,INFINITE));

第一参数,完成端口,相对于我们的仓库,第三个参数,相对于,快递公司的信息,0,是顺丰,第四个参数是

这个快递的信息,对应于程序里,就是,OverLapped结构体,里面保存着,传输多少字节,错误码之类的信息。

这个结构体,是在ReadFile,WriteFile函数最后一个参数传递的。

再说说,异步这个事。程序里就是,ReadFile,WriteFIle函数调用后,不用等待完成了,再往下执行,而是,这些读写

的任务交给了操作系统,你的线程该干嘛就干嘛去;这就好比,仓库老板和快递公司签了一件快递的合同,他不用等

快递到了,再去忙其他的事情,而是让其他员工去仓库等着这些快递的到来就好了。程序里就是让工作线程等着ReadFile,
WriteFile完成的通知,然后去处理就好了。
好了,大概要讲的就这些,下面附VS2010下面能跑的代码。只有一百行左右,非常简单。

#include "stdafx.h"

#include <Windows.h>
#include <stdio.h>

struct OverlappedInfo:public OVERLAPPED
{
	OverlappedInfo()
	{
		memset(this,0,sizeof(OVERLAPPED));
		memset(szMsg,0,64);
		memset(szBuffer,0,64);
	}
	char szMsg[64];
	char szBuffer[64];
};

struct ServerInfo
{
	int iThreadIndex;
	HANDLE hCompletionPort;
};

//IO请求完成后,工作线程用来处理数据
DWORD CALLBACK pfnThreadFun(LPVOID param)
{
	DWORD dwNumberOfBytesTransferred=0;
	ULONG ulCompletionKey=0;
	LPOVERLAPPED *lpOverlapped=NULL;
	ServerInfo* pServerInfo = (ServerInfo*)param;
	while(TRUE)
	{
		//若没有IO请求完成,会卡死在这里,类似WaitForOjbect系列函数等待内核对象一样
		if(!GetQueuedCompletionStatus(pServerInfo->hCompletionPort,&dwNumberOfBytesTransferred,
			(PULONG_PTR)&ulCompletionKey,(LPOVERLAPPED*)&lpOverlapped,INFINITE))
		{
			printf("error...\n");
		}
		else
		{
			//有数据来了,处理这些数据;其实这里的OverLapped结构地址,就是主线程那边创建的OverLappe结构的地址
			printf("Thread:%d;	ulCompletionKey:%ld;	ServerMsg:%s	ReadData:%s\n",
				pServerInfo->iThreadIndex,ulCompletionKey,((OverlappedInfo*)lpOverlapped)->szMsg,
				((OverlappedInfo*)lpOverlapped)->szBuffer);
		}
	}
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hFile[10];
	HANDLE hComPort;
	HANDLE hThread[5];

	for (int i = 0;i<10;i++)
	{
		TCHAR szFile[MAX_PATH] = {0};
		wsprintf(szFile,_T("./test_%d.txt"),i);
		//以CREATE_ALWAYS方式,创建十个文本文件,倒数第二个参数为FILE_FLAG_OVERLAPPED
		hFile[i] = ::CreateFile(szFile,GENERIC_WRITE|GENERIC_READ,
			FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_FLAG_OVERLAPPED,NULL);
		if(hFile[i]==INVALID_HANDLE_VALUE)
		{
			printf("文件打开失败..\n");
		}
	}

	//创建唯一一个完成端口
	hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,4);

	for (int i = 0;i<10;i++)
	{
		//将十个文件句柄与唯一一个完成端口绑定
		if(hComPort!=CreateIoCompletionPort(hFile[i],hComPort,i,0))
		{
			printf("CreateIoCompletionPort(hFile,hComPort,0,0) failed\n");
		}
	}
		
	ServerInfo serverInfo[5];
	for (int i = 0;i<5;i++)
	{
		
		serverInfo[i].hCompletionPort = hComPort;
		serverInfo[i].iThreadIndex = i;
		//创建工作线程
		hThread[i] = CreateThread(NULL,0,pfnThreadFun,&serverInfo[i],0,NULL);
	}
	
	DWORD dwWritten = 0;	
	for (int i = 0;i<10;i++)
	{
		OverlappedInfo oWrite ;
		sprintf(oWrite.szMsg,"write to test_%d.txt",i);
		char szData[64]={0};
		sprintf(szData,"file data from text_%d.txt",i);
		//IO异步请求
		WriteFile(hFile[i],szData,strlen(szData)+1,&dwWritten,&oWrite);
	}

	while(TRUE)
	{
		for (int i = 0;i<10;i++)
		{
			OverlappedInfo oRead;
			sprintf(oRead.szMsg,"Read from file test_%d.txt:",i);
			//IO异步请求,第二参数为从文件读取到的数据,因为oRead这个OverLapped 结构体
			//会传到GetQueuedCompletionStatus的倒数第二个参数,所以那里可以获取读到的数据
			ReadFile(hFile[i],oRead.szBuffer,64,NULL,&oRead);
			Sleep(1000);
		}		
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值