找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4200|回复: 0

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

[复制链接]
发表于 2012-2-29 15:03:56 | 显示全部楼层 |阅读模式
上一篇《IOCP浅析》中翻翻的谈了一下IOCP的简单含义,这篇稍微深入讨论下IOCP到底有什么好的,让大家将他推向神坛,同时简单的讨论下基本函数。
IOCP出现的意义?
写过网络程序的朋友应该很清楚网络程序的原型代码,startup一个WSADATA,然后建立一个监听socket对象,绑定一个服务器地址,然后开始监听,无限循环的accept来自客户端的消息,建立一个线程来处理消息,accept之后线程就被挂起了,知道收到来自客户端的消息。
这样的模型中服务器对每个客户端都会创建一个线程,优点在于等待请求的线程只做很少的事情,大部分时间该线程都在休息,因为recv函数是阻塞的。
所以这样的效率并不是很高,NT小组意识到这样CPU的大部分时间都耗费在线程的上下文切换上,线程并没有抢到cpu时间来处理自己的工作。
NT小组想到了一个解决办法,实现开好N个线程,将用户的消息都投递到一个消息队列中去,然后事先开好的N个线程逐一从消息队列中取出消息并加以处理,就可以避免为每一个客户端的请求单独开线程,既减少了线程的资源,也提高了线程的利用率。所以I/O完成端口的内核对象在NT3.5中首次被引入,MS还是比较伟大的。
这里你也看到了,IOCP其实称作是一种消息处理的机制差不多,而叫完成端口估计也是有历史原因,亦或者是因为他提供了用户与操作系统的一种接口吧。
ICOP的基本函数接口
创建完成端口
  1. HANDLE WINAPI CreateIoCompletionPort(
  2.         __in      HANDLE FileHandle,                                // An open file handle or INVALID_HANDLE_VALUE
  3.         __in_opt  HANDLE ExistingCompletionPort,        // A handle to an existing I/O completion port or NULL
  4.         __in      ULONG_PTR CompletionKey,                        // Completion key
  5.         __in      DWORD NumberOfConcurrentThreads        // Number of threads to execute concurrently
  6.         );
复制代码
第一个参数是指一个已经打开的文件句柄或者空句柄值,一般为客户端的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的异步调用
  1. BOOL WINAPI PostQueuedCompletionStatus(
  2.   __in      HANDLE CompletionPort,
  3.   __in      DWORD dwNumberOfBytesTransferred,
  4.   __in      ULONG_PTR dwCompletionKey,
  5.   __in_opt  LPOVERLAPPED lpOverlapped
  6. );
复制代码
第一个参数为创建的完成端口句柄
第二个参数传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer,其结构如下
  1. typedef struct _OVERLAPPED {
  2.         ULONG_PTR Internal;
  3.         ULONG_PTR InternalHigh;
  4.         union {
  5.                 struct {
  6.                         DWORD Offset;
  7.                         DWORD OffsetHigh;
  8.                 };
  9.                 PVOID  Pointer;
  10.         };
  11.         HANDLE    hEvent;
  12. } OVERLAPPED, *LPOVERLAPPED;
复制代码
线程的同步
  1. BOOL WINAPI GetQueuedCompletionStatus(
  2.   __in   HANDLE CompletionPort,
  3.   __out  LPDWORD lpNumberOfBytes,
  4.   __out  PULONG_PTR lpCompletionKey,
  5.   __out  LPOVERLAPPED *lpOverlapped,
  6.   __in   DWORD dwMilliseconds
  7. );
复制代码
第一个参数为创建的完成端口句柄
第二个参数同样为传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠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就介绍到这里,下一篇会尝试着写出一个简单的完成端口模型来通讯,这篇可能会比较晚出来,因为自己也是摸索阶段,大家互勉。

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-28 15:26 , Processed in 0.012087 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表