完成埠(上) (轉)

gugu99發表於2008-01-27
完成埠(上) (轉)[@more@]

完成埠

完成埠是到目前為止最為複雜的輸入輸出模式。然而,當一個應用不得不同時處理大量的socket時,它也提供了使達到最佳的可能性。不幸的是,完成埠只能用在 NT和上。由於完成埠被設計得極為複雜,它應該成為員的青年禁衛軍,只有在被迫面對幾百甚至幾千個併發的socket、你又希望在新增後可以獲得更好的scale時,才被派上戰場。關於完成埠,最重要的是記住這一點:如果你為winnt/2000開發處理大量socket I/O 請求的高效能服務,它是你的最佳選擇(比如,服務)。

本質上完成埠模式要求你建立一個完成埠來管理重疊i/o請求,用一定數量的執行緒來處理已完成的重疊i/o請求.注意,事實上完成埠是win32,winnt,的內建的,它能操作的不僅僅是socket控制程式碼。但是,本章將把討論範圍侷限於在socket控制程式碼上下文中,如何利用完成埠的優勢。
在開始使用完成埠模式之前,我們必須建立一個完成埠物件,用它來管理任意數量的socket控制程式碼上的多I/O請求。完成這一動作需要CreateIoCompletionPort,它具有如下形式的定義:
HANDLE CreateIoCompletionPort(
 HANDLE FileHandle,
 HANDLE ExistingCompletionPort,
 D CompletionKey,
 DWORD NumberOfConcurrentThreads
);

在瞭解引數的細節之前,要明白這個函式事實上有兩個目的:
 。建立一個完成埠物件
 。把一個控制程式碼關聯到完成對口上。
 
開始建立完成埠時,我們唯一感興趣的引數是NumberOfConcurrentThreads,前面的三個引數可以忽略不計。引數NumberOfConcurrentThreads用來指定在一個完成埠上可以併發的執行緒數量。理想的情況是,一個上只執行一個執行緒,這樣可以避免執行緒上下文切換的開銷。如果這個引數的值為0,那就是告訴系統執行緒數與處理器數相同。我們可以用下面的程式碼來建立I/O完成埠。
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
 NULL, 0, 0);
這段程式碼返回一個控制程式碼,在關聯socket控制程式碼時,它用來標識這裡的完成埠。

工作者執行緒和完成埠

成功的建立了完成埠物件,就可以把socket控制程式碼(注意,原文用的是handles,複數)關聯上去。可是在做這一步之前,還有一件必須完成的工作:建立一個或多個工作者執行緒,當socketI/O 請求被投遞到完成埠物件時,這些執行緒為完成埠服務。說到這裡,你可能想知道應該建立多少個執行緒來為完成埠服務。事實上這是完成埠模式更為複雜的一面,因為這需要你通盤考慮整個應用的設計,才能決定用多少個執行緒來為I/O請求服務。注意到這一點是很重要的:在呼叫CreateIoCompletionPort時指定的併發執行緒的個數,和建立的工作者執行緒的個數是有區別的,
或者說,它們不是一回事。我們在前面推薦的做法,是呼叫CreateIoCompletionPort時指定每個處理器上只有一個執行緒,以避免執行緒上下文切換的開銷。CreateIoCompletionPort的引數NumberOfConcurrentThreads明確的告訴系統,每次只允許n個執行緒可以操作完成埠。如果你為一個完成埠建立的工作者執行緒比n多,那一次只能有n個執行緒可以進行操作(確切地說,在一小段時間內,系統啟用的執行緒有可能超過n,但系統會很快將這個數量減小到n)。你可能會覺得奇怪:我明明已經在CreateIoCompletionPort中指定了一個值,幹嗎要建立比它多的工作者執行緒。
正如我前面提到的,這取決於你的整個應用的設計。如果一個工作者執行緒呼叫sleep、WaitForSingle之類的函式,然後,它掛了,另一個執行緒就可以取代它的位置。或者說,你總是希望有足夠多可以的執行緒,來滿足你在CreateIoCompletionPort指定的那一個數字。這樣,如果你預見到工作者執行緒可能阻塞,你就找到了一個理由,來建立比CreateIoCompletionPort的引數NumberOfConcurrentThreads多的工作者執行緒。


 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-998545/,如需轉載,請註明出處,否則將追究法律責任。

相關文章