西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页编程开发VC|VC++ → I/O完成端口的实现-Windows编程技巧

I/O完成端口的实现-Windows编程技巧

相关软件相关文章发表评论 来源:本站整理时间:2010/10/22 12:21:40字体大小:A-A+

作者:佚名点击:706次评论:0次标签: Windows 编程 完成端口

  • 类型:文字输入大小:8KB语言:中文 评分:5.0
  • 标签:
立即下载
2 页 使用I/O完成端口

使用I/O完成端口
应用程序将IoCompletion执行体对象当作与多个文件句柄相关的I/O完成的核心。一旦一个文件与一个完成端口相关联,任何在此文件上异步I/O操作的完成都会导致一个完成通知包(completion notification packet)加入到完成端口队列。一个线程只需简单的等待一个完成通知包被排队到此完成端口上,就可以等待在多个文件上的所有正在进行之中的I/O操作的完成事件。Windows API中的WaitForMultipleObjects 提供了类似的功能,但完成端口的优点在于在系统的协助下发挥高效的并发性。这里的并发性可以理解为应用程序主动处理客户请求的线程的数量的多少。

当应用程序创建一个完成端口时,需要设定并发量。该数值指示了在任何给定时候正在运行的与该端口相关联的线程的最大数量。正如前面所提到的,理想情况是在任何给定的时刻,系统中每个处理器都有一个线程在运行。Windows利用与一个端口相关联的并发值参数来控制一个应用程序中活动线程的数量。如果与一个端口相关的活动线程数达到并发值,那么,在这个端口上等待的线程将不允许再运行了。相反,它将等待某个活动线程处理完当前操作并检查是否有别的包正在该端口上等待。如果有的话,该线程只是简单的抓获该包然后处理。在这个过程中,没有上下文切换,CPU得到最大限度的利用。

下图1显示了一个完成端口操作流程的高度图解。客户请求将导致一个I/O包(IRP)被排队到完成端口。操作系统允许不超过并发量上限(即上面提到的那个并发值)的多个线程并发地处理客户端请求。直到一些活动线程因I/O请求而阻塞,等待线程才能被激活。下面我们将做进一步的探讨。

 创建完成端口需要调用Windows API CreateIoCompletionPort:

HANDLE CreateIoCompletionPort(
  HANDLE FileHandle,
  HANDLE ExistingCompletionPort,
  DWORD CompletionKey,
  DWORD NumberOfConcurrentThreads
);

创建一个完成端口时,通常对参数ExistingCompletionPort赋值NULL, NumberOfConcurrentThreads参数定义了在完成端口上同时允许执行的线程数量。如果有文件句柄传递给FileHandle参数,则该文件与完成端口关联在了一起。当这个文件上的I/O请求完成时,一个完成通知包将被投递到完成端口消息队列中。另外一个API GetQueuedCompletionStatus是用来获取排队完成状态,它使调用线程挂起,直到收到一个完成通知包。

BOOL GetQueuedCompletionStatus(
  HANDLE CompletionPort,
  LPDWORD lpNumberOfBytesTransferred,
  LPDWORD CompletionKey,
  LPOVERLAPPED* lpOverlapped,
  DWORD dwMiillisecondTimeout
);

完成端口实际上是在管理一个线程池,它会记录当前活动(即没有被I/O等事件阻塞)的线程数。当有完成通知包到达该端口时,在该端口上等待的线程按照后进先出(LIFO)的次序被唤醒,因此最近(most recently)被阻塞的线程就是获得下一个完成通知包的线程。那些长时间得不到响应的的线程的堆栈将会被从内存调到磁盘交换区去等待,当与一个端口关联的线程太多超过了当前的处理能力时,就可以将长时间阻塞的线程占用的内存减到最少。

服务器应用程序往往通过网络端点来接受客户请求,而这些网络端点是由文件句柄来表示的。这样的例子包括Windows Sockets 2(Winsock2)套接字或者命名管道。当服务器创建它的通信端点时,它将这些通信端点与一个完成端口关联起来,并且它的线程通过调用GetQueuedCompletionStatus来等待此端口上进来的完成通知。当一个线程在此完成端口上得到一个I/O完成通知包时,它便不再等待,开始处理I/O结果数据,从而变成一个活动的线程。一个线程在处理过程中可能将阻塞很多次,比如当它需要从磁盘上的文件读取数据时,或者当它需要与其他的线程同步时。Windows NT检测到这些活动,并且识别出该完成端口上至少已经有一个活动线程。因此,当活动线程由于I/O请求而阻塞时,如果在队列中存在一个包,则唤醒另一个正在此完成端口上等待的线程提供处理服务。

微软的指导原则是,将并发值设置成大约等于该系统中处理器的数目。但是要注意,一个完成端口上实际活动线程数量有可能超过设置的并发值。考虑并发值被设置为1的情况,一个客户请求进来了,某个线程因为被调度来处理该请求而变成活动的。下一个请求到达时,正在该端口上等待的另一个线程却不允许执行,因为活动的线程数已经达到了设置的并发上限值。然后,当活动线程需要等待I/O而阻塞时,等待的线程将被激活,当它尚在活动时,上一个线程的I/O完成了,这使得它继续保持活动状态(继续执行数据处理服务)。此刻,一直到两个线程中有一个被阻塞,并发值始终是2,高于设置的并发上限值1。大多数时候,活动线程数将维持在设置的并发限制值上,或者超过一点。

应用程序通过调用PostQueuedCompletionStatus这个API向完成端口投递一个自定义的完成通知包。服务器一般通过该函数发送消息通知线程有外部事件发生,例如需要温和的关机。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)