I/O Completion Ports學習

表示仍是本身看MSDN最直接,別人的介紹都是嚼剩下,有木有?可憐windows

 

IO完成端口爲在多處理器系統處理多個異步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完成端口的最重要的性質是併發值。完成端口的併發值在經過CreateIoCompletionPorttheNumberOfConcurrentThreads參數被肯定。這個值限制了與完成端口相關聯的線程的數目。當關聯線程數目超過了這個併發值,系統將會阻塞任何以後的線程,直到運行線程數目降到併發值。

最有效的語義是當有完成包在隊列裏,但沒有等待會被知足由於端口已經達到併發限制。考慮到在併發值下,用一個或多個線程等待在GetQueuedCompletionStatus調用。在這種狀況下,若是隊列有完成包在等待,當運行線程調用GetQueuedCompletionStatus,他將不會阻塞,由於如上面提到的線程隊列是先進先出的。取而代之的是,這個線程將當即拿到下一個完成包。沒有上下文切換髮生,由於運行線程連續地拿完成包,另外的線程不能運行【這段都怎麼理解】。

注意

在前面的例子裏,額外的線程好像是無用的,而且不會容許,但假設運行線程由於某些同步機制從未進入等待狀態,中止或者關閉它關聯的完成端口。注意當從新設計應用的時候全部這些線程的執行分支。

最好的併發最大值是電腦的CPU個數。若是你的傳輸要求一個複雜的計算,這就須要大點的併發值。每一個完成包可能完成的時間增長,但更多的完成包被併發地處理。你能夠試驗設置併發值來達到程序的最優化。

系統運行當一關聯同一完成端口的線程由於一些緣由(例如SuspendThread函數)在等待狀態時,另外一線程等待在GetQueuedCompletionStatus來處理完成包。當這個在等待狀態的線程開始運行,當活躍線程數目超過併發值這將是一個短暫的過程。然而,系統將經過不容許任何啓動新的活躍線程迅速減小活躍線程數目,直到活躍線程數目降低到併發值。這也是你能夠在線程池裏建立比並發值多的線程的緣由。線程池管理超越了本話題的範圍,可是一個好的經驗是在線程池裏最少擁有系統處理器兩倍的線程數(>=2*corenum)。能夠參考 Thread Pools

支持的IO函數

下列的函數能夠被用來經過利用完成端口來啓動IO操做。你必須傳遞OVERLAPPED結構的一個實例和以前與IO關聯的描述符給這些函數(經過調用CreateIoCompletionPort)來開啓IO完成端口機制:

 

ok,翻譯完了,不少句子不通順啊,有的地方本身都不明白啊!

相關文章
相關標籤/搜索