I/O 完成端口

Windows 提供一种称为I/O完成端口(I/O Completion Port)机制,能够让I/O的完成处理交由一个专门的线程池来完成,而线程池的线程数量是一个可配置的参数。这种做法将I/O请求的发起动作与完成处理分离到了不同的线程中,通过调节I/O完成端口的并行度(即线程池的线程数)使得系统处理客户请求的吞吐量最大化。

I/O完成端口是内核对象,类型为IoCompletionObjectType。I/O完成端口是内核队列对象的一个应用,数据结构等同于KQUEUE。

I/O完成端口的用法及其实现原理:

  1. 应用程序调用CreateIoCompletionPort 创建一个I/O完成端口对象,对应的系统服务为NtCreateIoCompletion。NtCreateIoCompletion 参数count 指定了该完成端口允许多少个线程并发运行。它创建一个类型为IoCompletionObjectType 的KQUEUE对象,然后调用KeInitializeQueue 初始化该KQUEUE对象,设置线程数,以及初始化其内部各个链表,最后将该完成端口对象插入到进程的句柄表中。
  2. 应用程序在调用CreateIoCompletionPort 时为该文件指定一个完成键(CompletionKey 参数)。对应调用的系统服务是NtSetInformationFile,其中文件信息类别为FileCompletionInformation。NtSetInformationFIle 申请一个IO_COMPLETION_CONTEXT对象,只包含Port和Key成员,其中Port 被初始化为参数中指定的端口对象,Key被初始化为参数FileInfomation中指定的Key。凡是加入完成端口的文件对象都必须以异步方式(即FILE_FLAG_OVERLAPPED标志)创建,否则返回STATUS_INVALID_PARAMETER。NtSetInformationFile 为文件对象设置了完成端口,则该文件对象的CompletionContext 将指向IO_COMPLETION_CONTEXT对象。
  3. IopCompleteRequest 调用KeInsertQueue ,将IRP对象的Tail部分的I/O完成包插入到完成端口队列中。
  4. 应用程序调用GetQueuedCompletionStatus 试图从I/O 完成端口的队列中获得一个I/O完成包。对应的系统服务是NtRemoveIoCompletion,它首先对参数进行检查,然后调用KeRemoveQueue ,试图从完成端口的队列中移除一个I/O完成包,若成功获取到,则释放IRP对象,并通过NtRemoveIoCompletion的输出参数返回必要的I/O完成状态信息。

总结:NtCreateIoCompletion 调用KeInitializeQueue 初始化一个KQUEUE对象;NtSetInformationFile 将完成端口对象的信息设置到文件对象的CompletionContext 中;IopCompleteRequest 调用KeInsertQueue,将I/O请求的完成处理转交给完成端口对象;最后NtRemoveIoCompletion 调用KeRemoveQueue ,从完成端口的队列中获得一个I/O请求的完成状态信息。

I/O完成端口的工作原理,如图:

Windows的KQUEUE队列对象是一种内核机制,它跟踪一个队列对象中的线程是否在执行。当一个线程获得了一个I/O完成包时,它便进入活动状态,完成端口的活动线程数加1,若该线程进入等待,则完成端口的活动线程数减1。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值