Windows核心編程 - 異步I/O之完成端口

1. 背景

    構建一個服務應用程序,常用的主要有兩種模型: 串行模型和並行模型。

    1)串行模型: 一個線程等待一個請求,當請求到達時,線程被喚醒對請求進行處理;處理完後再接着等待下一個請求。

           缺點:不能同時處理多個請求。

     2)並行模型:一個線程等待一個請求,當請求到達時,線程會創建一個新的線程來處理請求。然後線程進入下一次循環等待下一個請求。新的線程處理完請求後,會自行終止。

          缺點:如果請求數量較多,需要創建相對數量的線程,一方面線程頻繁地創建、終止會帶來開銷;另一方面,線程數量過多,但實際上機器的CPU數量有限,且這些線程大多都是處於可調度的狀態,那麼內核需花費很多在線程的切換上下文的過程,導致沒有多少CPU時間來執行真正需要的任務。 I/O完成端口內核對象可解決此類問題。

 

2. 創建I/O完成端口

        I/O完成端口會對併發運行的線程數量設定一個上限,即線程數量不能隨着請求個數增加而線性增長,一般是根據機器本身的CPU個數來選擇一個合適的上限,以減少內核執行線程上下文切換的花銷。在應用程序初始化的時候,會創建一個線程池,並讓線程池中的線程在應用程序運行期間處於可調用度狀態,得以提高服務應用程序的性能。

        創建I/O完成端口的函數用: CreateIoCompletionPort(),此函數有參數可指定線程池的大小。當創建一個I/O完成端口時,系統內核會創建5個不同的數據結構:

      1)設備列表:表示與該端口相關聯的一個或多個設備;

      2)I/O完成隊列(先入先出):當設備的一個異步I/O請求完成時,設備會檢查該設備是否與一個I/O完成端口相關聯,如果是則將該已完成的I/O請求追加到I/O完成隊列;

      3)等待線程隊列(後入先出):當線程池中的每個線程調用GetQueueCompletionStatus()時,調用線程的線程ID會被添加到等待線程隊列,這是告知I/O完成端口內核對象,有哪些線程在等待處理已完成的I/O請求,當I/O完成隊列中出現一項時,I/O完成端口就會喚醒等待線程隊列中的一個線程來進行處理。該隊列是後入先出的,假設有3個線程在等待線程隊列中,當I/O完成隊列出現一個項時,則最後調用GetQueueCompletionStatus()的線程3會被喚醒來處理這個項。線程3處理完這個項後,會再次調用GetQueueCompletionStatus()進入等待線程隊列,這時如果I/O完成隊列又來了一項,則線程3會被再次喚醒來處理這個項。

      4)已釋放線程列表:當完成端口在等待線程隊列中喚醒的線程或已暫停的線程被喚醒,都會進入到已釋放線程列表;

      5)已暫停線程列表:如果一個已釋放的線程,在工作過程中切換到了等待狀態,則會被放入到已暫停線程列表。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章