IOCP浅析[二]——IOCP出现的意义和函数接口

上一篇《IOCP浅析》中翻翻的谈了一下IOCP的简单含义,这篇稍微深入讨论下IOCP到底有什么好的,让大家将他推向神坛,同时简单的讨论下基本函数。

IOCP出现的意义?

写过网络程序的朋友应该很清楚网络程序的原型代码,startup一个WSADATA,然后建立一个监听socket对象,绑定一个服务器地址,然后开始监听,无限循环的accept来自客户端的消息,建立一个线程来处理消息,accept之后线程就被挂起了,知道收到来自客户端的消息。

这样的模型中服务器对每个客户端都会创建一个线程,优点在于等待请求的线程只做很少的事情,大部分时间该线程都在休息,因为recv函数是阻塞的。

所以这样的效率并不是很高,NT小组意识到这样CPU的大部分时间都耗费在线程的上下文切换上,线程并没有抢到cpu时间来处理自己的工作。

NT小组想到了一个解决办法,实现开好N个线程,将用户的消息都投递到一个消息队列中去,然后事先开好的N个线程逐一从消息队列中取出消息并加以处理,就可以避免为每一个客户端的请求单独开线程,既减少了线程的资源,也提高了线程的利用率。所以I/O完成端口的内核对象在NT3.5中首次被引入,MS还是比较伟大的。

这里你也看到了,IOCP其实称作是一种消息处理的机制差不多,而叫完成端口估计也是有历史原因,亦或者是因为他提供了用户与操作系统的一种接口吧。

ICOP的基本函数接口
创建完成端口

HANDLE WINAPI CreateIoCompletionPort(
	__in      HANDLE FileHandle,				// An open file handle or INVALID_HANDLE_VALUE
	__in_opt  HANDLE ExistingCompletionPort,	// A handle to an existing I/O completion port or NULL
	__in      ULONG_PTR CompletionKey,			// Completion key
	__in      DWORD NumberOfConcurrentThreads	// Number of threads to execute concurrently
	);

第一个参数是指一个已经打开的文件句柄或者空句柄值,一般为客户端的socket 注意:第一个参数HANDLE在创建时需要在CreateFile()中制定FILE_FLAG_OVERLAPPED标志。
第二个参数是指一个已经存在的IOCP句柄或者NULL
第三个参数是指完成Key,是一个unsigned long的指针,可以为NULL
第四个参数才是我们比较关心的,是指已经创建好的线程数,一般我们会用一个公式来计算,预设的线程数 = CPU核心数 * 2 + 2,有人也说是 + 1,我是没明白为什么要这样计算,希望大神指教。

对于第三个参数的意思,MSDN上解释如下 Use the CompletionKey parameter to help your application track which I/O operations have completed.(用来检测那些IO操作已经完成)

该函数用于两个不同的目的

1.创建一个完成端口的句柄对象
HANDLE h = CreateIoCompletionPort((HANDLE) socket, hCompletionPort, dwCompletionKey, m_nIOWorkers);

2.将一个句柄和完成端口关联在一起

在绑定每一个CLIENT到IOCP时,需要传递一个DWORD CompletionKey, 该参数为CLIENT信息的一个指针。

IO的异步调用

BOOL WINAPI PostQueuedCompletionStatus(
  __in      HANDLE CompletionPort,
  __in      DWORD dwNumberOfBytesTransferred,
  __in      ULONG_PTR dwCompletionKey,
  __in_opt  LPOVERLAPPED lpOverlapped
);

第一个参数为创建的完成端口句柄
第二个参数传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer,其结构如下

typedef struct _OVERLAPPED {
	ULONG_PTR Internal;
	ULONG_PTR InternalHigh;
	union {
		struct {
			DWORD Offset;
			DWORD OffsetHigh;
		};
		PVOID  Pointer;
	};
	HANDLE    hEvent;
} OVERLAPPED, *LPOVERLAPPED;

线程的同步

BOOL WINAPI GetQueuedCompletionStatus(
  __in   HANDLE CompletionPort,
  __out  LPDWORD lpNumberOfBytes,
  __out  PULONG_PTR lpCompletionKey,
  __out  LPOVERLAPPED *lpOverlapped,
  __in   DWORD dwMilliseconds
);

第一个参数为创建的完成端口句柄
第二个参数同样为传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer
第五个参数的解释如下
The number of milliseconds that the caller is willing to wait for a completion packet to appear at the completion port. If a completion packet does not appear within the specified time, the function times out, returns FALSE, and sets *lpOverlapped to NULL.(等待完成端口上的完成packet出现的毫秒数。如果一个完成在特殊时间内没有出现,则认为超时,返回false,同时将重叠buffer置为NULL)

大体上函数就有这么几个,大家有兴趣可以去看看MSDN上关于完成端口上的英文介绍,比较准确,中文翻译上难免出现歧义,同时还可以锻炼英文阅读。

好了,I/O完成端口的API就介绍到这里,下一篇会尝试着写出一个简单的完成端口模型来通讯,这篇可能会比较晚出来,因为自己也是摸索阶段,大家互勉。

转自: http://www.cppfans.org/1089.html | C++爱好者博客™

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值