共用方式為


同步和異步 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 作業失敗。
  • 封鎖的線程會由系統終止;例如,進程本身已終止,或者另一個線程會使用封鎖線程的句柄呼叫 TerminateThread 函式。 (這通常被認為是最後的手段,而不是良好的應用程式設計。

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

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

注意

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

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

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

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

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

您也可以建立事件,並將句柄放在 OVERLAPPED 結構中;然後,等候函式可以等候 I/O 作業完成,方法是等候事件句柄。

如先前所述,使用異步句柄時,應用程式在判斷何時釋放與該句柄上指定I/O 作業相關聯的資源時,應該小心使用。 如果句柄過早地解除分配,ReadFile WriteFile 可能會錯誤地報告 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,則會有無雙重錯誤條件。 在此範例中,建議允許完成埠例程只負責這類資源的所有釋放作業。

系統不會在異步句柄上維護檔案指標,而支援檔案指標的檔案和裝置(也就是搜尋裝置),因此檔案位置必須傳遞至重疊結構相關位移數據成員中的讀取和寫入函式。 如需詳細資訊,請參閱 WriteFileReadFile

同步句柄的檔案指標位置由系統維護,因為數據是讀取或寫入的,也可以使用 SetFilePointer SetFilePointerEx 函式來更新。

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

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

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

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

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