OVERLAPPED結構主要用於非同步I/O操作,其資料結構定義如下:
typedef struct _OVERLAPPED {
DWORD Internal; // 系統保留,存放系統設定的狀態
DWORD InternalHigh; // 系統保留,存放被傳輸資料的長度
DWORD Offset; // 指定檔案的位置,檔案位置是相對檔案開始處的位元組位移量。
DWORD OffsetHigh; // 指定開始傳送資料的位元組位移量的高位字
HANDLE hEvent; // 標識事件,資料傳送完成時把它設為訊號狀態
}OVERLAPPED;
Overlapped I/O模型可以用以下幾種方式實現:
一、核心對象實現
1. 把裝置控制代碼看作同步對象,ReadFile將裝置控制代碼設定為無訊號。ReadFile非同步I/O位元組位置必須在OVERLAPPED結構中指定。
2. 完成I/O,設定資訊狀態為有訊號。
3. 通過WaitForSingleObject或WaitForMultipleObject判斷或者非同步裝置調用GetOverLappedResult函數。
二、事件核心對象實現
1. Overlapped成員hEven標識事件核心對象。CreateEvent,為每個請求建立一個事件,初始化每個請求的hEvent成員。調用WaitForMultipleObject來等其中一個或全部完成。
2. Event對象必須是手動重設,使用自動重設WaitForSingleObject()和 WaitForMultipleObjects()函數不會返回。
關於自動重設事件和手動重設事件
自動重設事件:WaitForSingleObject()和WaitForMultipleObjects()會等待事件到訊號狀態,隨後又自動將其重設為非訊號狀態,保證等待此事件的線程中只有一個會被喚醒。
手動重設事件:需要調用ResetEvent()才會重設事件。可能有若干個線程在等待同一事件,這樣當事件變為訊號狀態時,所有等待線程都可以運行了。 SetEvent()函數用來把事件對象設定成訊號狀態,ResetEvent()把事件對象重設成非訊號狀態,兩者均需事件物件控點作參數。
三、非同步程序呼叫
在一個Overlapped I/O完成之後,系統調用callback回呼函數。系統在裝置控制代碼有訊號狀態下,才會調用回呼函數,傳給它完成I/O請求的錯誤碼,傳輸位元組數和 Overlapped結構的地址。通過下面的五個函數可以設定訊號狀態:SleepEx,WaitForSingleObjectEx,WaitForMultipleObjectEx,SingalObjectAndWait,MsgWaitForMultipleObjectsEx。
四、完成連接埠
完成連接埠(I/O completion)的優點:不會限制handle個數,可處理成千上萬個串連。I/O completion port允許一個線程將一個請求暫時儲存下來,由另一個線程為它做實際服務。
並行存取模型與線程池:在典型的並行存取模型中,伺服器為每一個用戶端建立一個線程,如果很多客戶同時請求,則這些線程都是啟動並執行,那麼CPU就要一個個切換,CPU花費了更多的時間線上程切換,線程卻沒得到很多CPU時間。到底應該建立多少個線程比較合適呢,微軟體協助文檔上講應該是2*CPU個。但理想條件下最好線程不要切換,而又能象線程池一樣,重複利用。I/O完成連接埠就是使用了線程池。一個線程執行任務結束後不會銷毀,而是重新回到線程隊列中。