Windows服務器端編程-第二章 設備IO與線程間通訊-7-將設備與完成端口關聯

將設備與完成端口關聯

在建立I/O完成端口時,實際上內核建立了5個不一樣的數據結構,如表2-1所示。在繼續閱讀以前應該參考一下。
1.bmp
2.bmp
表2-1 I/O完成端口的內部工做機制
第一個數據是設備列表,表示關聯到完成端口的一個或幾個設備。經過調用CreateIoCompletionPort能夠將設備與端口關聯起來。我再次建立了本身的函數,AssociateDeviceWithCompletionPort,封裝對CreateIoCompletionPort的調用。數據結構

BOOL AssociateDeviceWithCompletionPort(HANDLE hCompPort, HANDLE hDevice, DWORD dwCompKey) {
   HANDLE h = CreateIoCompletionPort(hDevice, hCompPort, dwCompKey, 0);

   return(h == hCompPort);
}

AssociateDeviceWithCompletionPort在已存在的完成端口的設備列表添加一個。調用時須要將已有的完成端口的句柄(由先前的CreateNewCompletionPort調用返回),設備句柄(能夠是一個文件,一個SOCKET端口,郵件槽,管道等等),和完成鍵值(有意義的值;操做系統不會關心到底是什麼東西)傳入該函數。每次將設備和端口相關聯,系統就會將信息添加到完成端口的設備列表中。app


注意

CreateIoCompletionPort函數很複雜,建議在調用時要從意識上將其分爲兩個理由。複雜的一個好處是:能夠打開文件與建立新的完成端口。例如,下面的代碼打開文件和建立新的完成端口,並將文件與之關聯。全部針對該文件的I/O請求都在完成以後攜帶CK_FILE完成鍵值,而且端口容許多至兩個線程並行執行。異步

#define CK_FILE   1

HANDLE hfile = CreateFile(...);
HANDLE hCompPort = CreateIoCompletionPort(hfile, NULL, CK_FILE, 2);

第二個數據結構是I/O完成隊列。當設備的異步I/O請求完成時,系統檢查設備是否與完成端口相關聯,若是是,系統就將已完成的I/O請求添加到完成端口的I/O完成隊列中。隊列中的每一個包含了傳輸的字節數,在設備與端口關聯時設置的完成鍵值,I/O請求的OVERLAPPED結構指針,以及錯誤代碼。後面將討論如何將從隊列中刪除。函數


注意

產生一個設備I/O請求,且不將項加入到I/O完成端口的隊列中是可能的。一般這不是必須的,但有可能會遇到,例如,經過SOCKET發送數據,而且不關心數據是否發送與否。spa

要產生這樣的I/O請求,必須將OVERLAPPED結構的hEvent的成員置成一個有效的事件句柄,而且經過位或操做將最高位置爲1,像下面這樣:操作系統

Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

Overlapped.hEvent = (HANDLE) ((DWORD_PTR) Overlapped.hEvent | 1);

ReadFile(..., &Overlapped);

如今能夠產生I/O請求,傳入OVERLAPPED結構的地址給須要的函數(例如上面的ReadFile)。線程

若是不用建立一個事件就能夠中止I/O完成的隊列就最好了,例以下面的代碼。不過,它並不會起做用:指針

Overlapped.hEvent = 1;

ReadFile(..., &Overlapped);

另外,不要忘了在關閉事件句柄以前將其的低位復位:code

CloseHandle((HANDLE) ((DWORD_PTR) Overlapped.hEvent & ~1));
相關文章
相關標籤/搜索