共用方式為


同步和異步 I/O

另請參閱 I/O 相關範例應用程式

輸入/輸出 (I/O) 同步處理有兩種類型:同步 I/O 和異步 I/O。 異步 I/O 也稱為重疊 I/O。

同步檔案 I/O 中,線程會啟動 I/O 作業,並立即進入等候狀態,直到 I/O 要求完成為止。 執行異步檔案 I/O 的 線程會呼叫適當的函式,將 I/O 要求傳送至核心。 如果核心接受要求,呼叫端線程會繼續處理另一個作業,直到核心向線程發出 I/O 作業完成的訊號為止。 然後,它會中斷其目前的作業,並視需要處理來自 I/O 作業的數據。

下圖說明這兩種同步處理類型。

一個顯示同步和異步 I/O 的圖示截圖。

在預期 I/O 要求需要大量時間的情況下,例如大型資料庫的重新整理或備份或通訊連結緩慢,異步 I/O 通常是優化處理效率的好方法。 不過,對於相對快速的 I/O 作業,處理核心 I/O 要求和核心訊號的額外負荷可能會讓異步 I/O 變得不那麼有用,特別是需要進行許多快速 I/O 作業時。 在此情況下,同步 I/O 會更好。 如何完成這些工作的機制和實作詳細數據會根據所使用的裝置句柄類型以及應用程式的特定需求而有所不同。 換句話說,通常有多種方法可以解決問題。

同步和異步 I/O 考慮

如果開啟檔案或裝置以進行同步 I/O(即未指定 FILE_FLAG_OVERLAPPED),則對 WriteFile 等函式的後續呼叫可能會阻塞呼叫執行緒的執行,直到發生以下任一事件:

  • I/O 作業會完成 (在此範例中為數據寫入)。
  • 發生 I/O 錯誤。 (例如,管道從另一端關閉。
  • 呼叫本身發生錯誤(例如,一或多個參數無效)。
  • 進程中的另一個線程使用被封鎖線程的線程句柄呼叫 CancelSynchronousIo 函式,這會終止該線程的 I/O 作業,導致 I/O 操作失敗。
  • 封鎖的線程會由系統終止;例如,進程本身已終止,或者另一個線程會使用封鎖線程的句柄呼叫 TerminateThread 函式。 (這通常被認為是最後的手段,而不是良好的應用程式設計。

在某些情況下,應用程式的設計和目的可能無法接受此延遲,因此應用程式設計工具應該考慮搭配適當的線程同步處理物件使用異步 I/O,例如 I/O 完成埠。 如需線程同步處理的詳細資訊,請參閱 關於同步處理

一個進程透過在 CreateFile 呼叫中,於 dwFlagsAndAttributes 參數指定 FILE_FLAG_OVERLAPPED 旗標,以開啟用於異步 I/O 的檔案。 如果未 指定FILE_FLAG_OVERLAPPED ,則會針對同步 I/O 開啟檔案。 當檔案已針對異步 I/O 開啟時,會將指向重疊 I/O 結構的指標傳遞至 ReadFile 和 WriteFile 的呼叫。 執行同步 I/O 時,在 ReadFile 和 WriteFile呼叫中不需要此結構。

注意

如果檔案或裝置已針對異步 I/O 開啟,則後續使用 該句柄的 WriteFile 等函式呼叫通常會立即傳回,但也可以針對封鎖的執行以同步方式運作。 如需詳細資訊,請參閱 異步磁碟 I/O 在 Windows 上顯示為同步。

雖然 CreateFile 是用來開啟檔案、磁碟區、匿名管道和其他類似裝置的最常見函式,但也可以使用從SocketAccept函式等其他系統物件型別轉換的句柄來執行 I/O 作業。

要取得目錄物件的句柄,可以使用 CreateFile 函式與 FILE_FLAG_BACKUP_SEMANTICS 屬性。 幾乎永遠不會使用目錄句柄—備份應用程式是通常會使用這些句柄的其中一個應用程式。

開啟異步 I/O 的檔案對象之後,必須正確建立、初始化 和傳遞至ReadFileWriteFile 等函式的每個呼叫重疊結構。 在異步讀取和寫入作業中使用 OVERLAPPED 結構時,請記住下列事項:

  • 在檔案物件的所有異步 I/O 作業都完成之前,請勿解除配置或修改 重疊 結構或數據緩衝區。
  • 如果您將 重迭結構的 指標宣告為局部變數,在檔案物件的所有異步 I/O 作業都完成之前,請勿結束本機函式。 如果本地函數過早退出,OVERLAPPED 結構將會超出作用域,且 ReadFileWriteFile 函數將無法存取在該函數範圍外遇到的這些結構。

您也可以建立事件,並將句柄放在 重疊 結構中;然後,使用 等待函式 來透過等候事件句柄以完成 I/O 作業。

如先前所述,使用異步句柄時,應用程式在判斷何時釋放與該句柄上指定I/O 作業相關聯的資源時,應該小心使用。 如果句柄過早地解除分配,ReadFileWriteFile 可能錯誤地顯示 I/O 操作已完成。 此外,WriteFile 函式有時會以 getLastError 值為 ERROR_SUCCESS 傳回 TRUE,即使它使用的是異步句柄(也可以使用 ERROR_IO_PENDING 傳回 FALSE)。 習慣於同步 I/O 設計的程式設計人員通常此時會釋放數據緩衝區資源,因為 TRUEERROR_SUCCESS 表示作業已完成。 不過,如果 I/O 完成埠 正與這個異步句柄搭配使用,即使 I/O 作業立即完成,也會傳送完成封包。 換句話說,如果應用程式在 WriteFile 傳回 TRUE之後釋放資源,除了 I/O 完成埠例程中之外,ERROR_SUCCESS,則會有無雙重錯誤條件。 在此範例中,建議允許完成埠例程只負責這類資源的所有釋放作業。

系統不會在異步控制代碼中維護檔案指標,對於支援檔案指標的檔案和設備(即具備搜尋功能的設備),因此必須將檔案位置傳遞給 OVERLAPPED 結構中相關位移數據成員的讀取和寫入函式。 如需詳細資訊,請參閱 WriteFileReadFile

當數據被讀取或寫入時,系統會維護同步句柄的檔案指標位置,並且也可以使用 SetFilePointerSetFilePointerEx 函式進行更新。

應用程式也可以等候檔句柄來同步處理 I/O 作業的完成,但這樣做需要非常謹慎。 每次啟動 I/O 作業時,操作系統會將檔句柄設定為未簽署的狀態。 每次 I/O 作業完成時,操作系統會將檔句柄設定為訊號狀態。 因此,如果應用程式啟動兩個 I/O 作業,並在檔句柄上等候,則無法判斷當句柄設定為訊號狀態時完成的作業。 如果應用程式必須在單一檔案上執行多個異步 I/O 作業,它應該在每個 I/O 作業的特定 OVERLAPPED 結構中等候事件句柄,而不是在一般檔句柄上等候。

取消 I/O 作業

若要取消所有暫止的異步 I/O 作業,請使用下列其中一項:

  • CancelIo:此函式只會取消呼叫線程針對指定之檔句柄發出的作業。
  • CancelIoEx:此函式會取消指定之檔句柄之線程發出的所有作業。

使用 CancelSynchronousIo 取消暫止的同步 I/O 作業。

ReadFileExWriteFileEx 函式可讓應用程式指定在異步 I/O 要求完成時執行的例程(請參閱 FileIOCompletionRoutine)。

寫入檔案

讀取檔