表示仍是本身看MSDN最直接,别人的介绍都是嚼剩下,有木有?windows
IO完成端口为在多处理器系统处理多个异步IO请求提供一个高效的线程模型。当一个进程新建一个完成端口,操做系统新建一个目的为服务这些请求的队列对象。经过利用IO完成端口与相关联的预先分配的线程池而不是新建线程来处理当前请求,处理多个并发的异步IO请求会更快更有效。网络
函数CreateIoCompletionPort建立一个IO完成端口,并在这个端口上关联一个或多个file【文件描述符】。当在这些操做符上的一个或者多个的一个异步IO操做完成时,一个IO完成包(packet)就进入与IO完成端口关联的先进先出队列。这个机制的一个强大的用法是在单个对象里进行多个描述符间的同步,尽管他们还有其余有用的应用。请注意:在队列中的数据包可能会以不一样的顺序出列。【这句不怎么理解,是否是多个线程在出列操做?】并发
注意:异步
属于file handle是表明重叠IO端点的一种系统抽象表明,而不仅是磁盘上的file。例如,能够是网络端点,TCP socket,命名管道或者mail slot。任何支持完成端口的系统对象均可以被利用。socket
When a file handle is associated with a completion port, the status block passed in will not be updated until the packet is removed from the completion port. The only exception is if the original operation returns synchronously with an error. A thread (either one created by the main thread or the main thread itself) uses the GetQueuedCompletionStatus function to wait for a completion packet to be queued to the I/O completion port, rather than waiting directly for the asynchronous I/O to complete. Threads that block their execution on an I/O completion port are released in last-in-first-out (LIFO) order, and the next completion packet is pulled from the I/O completion port's FIFO queue for that thread. This means that, when a completion packet is released to a thread, the system releases the last (most recent) thread associated with that port, passing it the completion information for the oldest I/O completion.async
当描述符与一个完成端口相关联,传进来的状态快不会被更新直到包从完成端口上拿走。惟一的异常是原来的操做异步返回错误。一个线程(能够是主线程建立的或者主线程本身)用GetQueuedCompletionStatus 函数来等待进入完成端口的包,而不是直接等待异步IO完成。在完成端口阻塞操做的线程会之后进显出释放,而这个线程的下一个端口包会以先进先出队列从IO端口取出。这就意味着,当一个包喂给了一个线程,系统将释放最后一个与端口关联的线程,同时为最老的完成端口传递完成端口信息【这句没怎么看懂】。函数
尽管任何线程都能向特定的完成端口调用GetQueuedCompletionStatus,当一个具体的线程第一次调用它时,它开始与特定的完成端口关联知道如下三种状况中的一种发生:优化
1.线程存在,关联了另一个完成端口;spa
2.关闭了完成端口。操作系统
也就是说一个线程只能关联一个完成端口。
当一个完成包被放入完成端口的队列中,系统首先检查当前有多少与端口关联的线程。若是运行中的线程数目小于并发值,最近的一个等待线程被容许处理完成包。当一个运行线程完成处理,它将要继续再次调用GetQueuedCompletionStatus,由于在这个点它要么等待下一个完成包,要么等待到包队列为空。
线程能够调用PostQueuedCompletionStatus来投递完成包到IO端口的队列。经过这样作,完成端口能够用来收取其余线程或者进程的交互数据,还能够从IO系统收取完成端口包。PostQueuedCompletionStatus函数容许应用程序不开启异步IO操做,就能向IO完成端口投递特定的完成包。好比,这对于之外不事件通知工做线程是有用的。
IO完成端口句柄和每一个描述符句柄与特定IO完成端口关联被认为提领了完成端口,当没有与它关联的引用时完成端口被释放。所以,全部这些句柄必须被适合地关心以释放完成端口和它关联的系统资源。这些条件知足后,经过调用CloseHandle来关闭完成端口句柄。
注意
一个完成端口与建立它的进行关联,不能被进程间共享。然而,单个句柄能够在同一进程的不一样线程中共享。
IO完成端口的最重要的性质是并发值。完成端口的并发值在经过CreateIoCompletionPort的theNumberOfConcurrentThreads参数被肯定。这个值限制了与完成端口相关联的线程的数目。当关联线程数目超过了这个并发值,系统将会阻塞任何以后的线程,直到运行线程数目降到并发值。
最有效的语义是当有完成包在队列里,但没有等待会被知足由于端口已经达到并发限制。考虑到在并发值下,用一个或多个线程等待在GetQueuedCompletionStatus调用。在这种状况下,若是队列有完成包在等待,当运行线程调用GetQueuedCompletionStatus,他将不会阻塞,由于如上面提到的线程队列是先进先出的。取而代之的是,这个线程将当即拿到下一个完成包。没有上下文切换发生,由于运行线程连续地拿完成包,另外的线程不能运行【这段都怎么理解】。
注意
在前面的例子里,额外的线程好像是无用的,而且不会容许,但假设运行线程由于某些同步机制从未进入等待状态,中止或者关闭它关联的完成端口。注意当从新设计应用的时候全部这些线程的执行分支。
最好的并发最大值是电脑的CPU个数。若是你的传输要求一个复杂的计算,这就须要大点的并发值。每一个完成包可能完成的时间增长,但更多的完成包被并发地处理。你能够试验设置并发值来达到程序的最优化。
系统运行当一关联同一完成端口的线程由于一些缘由(例如SuspendThread函数)在等待状态时,另外一线程等待在GetQueuedCompletionStatus来处理完成包。当这个在等待状态的线程开始运行,当活跃线程数目超过并发值这将是一个短暂的过程。然而,系统将经过不容许任何启动新的活跃线程迅速减小活跃线程数目,直到活跃线程数目降低到并发值。这也是你能够在线程池里建立比并发值多的线程的缘由。线程池管理超越了本话题的范围,可是一个好的经验是在线程池里最少拥有系统处理器两倍的线程数(>=2*corenum)。能够参考 Thread Pools。
下列的函数能够被用来经过利用完成端口来启动IO操做。你必须传递OVERLAPPED结构的一个实例和以前与IO关联的描述符给这些函数(经过调用CreateIoCompletionPort)来开启IO完成端口机制: