I/O Sinkron dan Asinkron

Lihat juga aplikasi sampel terkait I/O.

Ada dua jenis sinkronisasi input/output (I/O): I/O sinkron dan I/O asinkron. I/O asinkron juga disebut sebagai I/O yang tumpang tindih.

Dalam I/O file sinkron, utas memulai operasi I/O dan segera memasuki status tunggu hingga permintaan I/O selesai. Utas yang melakukan I/O file asinkron mengirimkan permintaan I/O ke kernel dengan memanggil fungsi yang sesuai. Jika permintaan diterima oleh kernel, utas panggilan terus memproses pekerjaan lain sampai kernel memberi sinyal ke utas bahwa operasi I/O selesai. Kemudian mengganggu pekerjaannya saat ini dan memproses data dari operasi I/O seperlunya.

Dua jenis sinkronisasi diilustrasikan dalam gambar berikut.

i/o sinkron dan asinkron

Dalam situasi di mana permintaan I/O diperkirakan akan memakan banyak waktu, seperti refresh atau pencadangan database besar atau tautan komunikasi yang lambat, I/O asinkron umumnya merupakan cara yang baik untuk mengoptimalkan efisiensi pemrosesan. Namun, untuk operasi I/O yang relatif cepat, overhead pemrosesan permintaan I/O kernel dan sinyal kernel dapat membuat I/O asinkron kurang bermanfaat, terutama jika banyak operasi I/O cepat yang perlu dilakukan. Dalam hal ini, I/O sinkron akan lebih baik. Mekanisme dan detail implementasi tentang cara menyelesaikan tugas-tugas ini bervariasi tergantung pada jenis handel perangkat yang digunakan dan kebutuhan khusus aplikasi. Dengan kata lain, biasanya ada beberapa cara untuk menyelesaikan masalah.

Pertimbangan I/O Sinkron dan Asinkron

Jika file atau perangkat dibuka untuk I/O sinkron (yaitu, FILE_FLAG_OVERLAPPED tidak ditentukan), panggilan berikutnya ke fungsi seperti WriteFile dapat memblokir eksekusi utas panggilan hingga salah satu peristiwa berikut terjadi:

  • Operasi I/O selesai (dalam contoh ini, penulisan data).
  • Terjadi kesalahan I/O. (Misalnya, pipa ditutup dari ujung lainnya.)
  • Kesalahan dilakukan dalam panggilan itu sendiri (misalnya, satu atau beberapa parameter tidak valid).
  • Utas lain dalam proses memanggil fungsi CancelSynchronousIo menggunakan handel utas utas yang diblokir, yang mengakhiri I/O untuk utas tersebut, gagal dalam operasi I/O.
  • Utas yang diblokir dihentikan oleh sistem; misalnya, proses itu sendiri dihentikan, atau utas lain memanggil fungsi TerminateThread menggunakan handel utas yang diblokir. (Ini umumnya dianggap sebagai upaya terakhir dan desain aplikasi yang tidak baik.)

Dalam beberapa kasus, penundaan ini mungkin tidak dapat diterima oleh desain dan tujuan aplikasi, sehingga perancang aplikasi harus mempertimbangkan untuk menggunakan I/O asinkron dengan objek sinkronisasi utas yang sesuai seperti port penyelesaian I/O. Untuk informasi selengkapnya tentang sinkronisasi utas, lihat Tentang Sinkronisasi.

Proses membuka file untuk I/O asinkron dalam panggilannya ke CreateFile dengan menentukan bendera FILE_FLAG_OVERLAPPED di parameter dwFlagsAndAttributes . Jika FILE_FLAG_OVERLAPPED tidak ditentukan, file dibuka untuk I/O sinkron. Ketika file telah dibuka untuk I/O asinkron, penunjuk ke struktur TUMPANG TINDIH diteruskan ke panggilan ke ReadFile dan WriteFile. Saat melakukan I/O sinkron, struktur ini tidak diperlukan dalam panggilan ke ReadFile dan WriteFile.

Catatan

Jika file atau perangkat dibuka untuk I/O asinkron, panggilan berikutnya ke fungsi seperti WriteFile menggunakan handel tersebut umumnya segera kembali tetapi juga dapat berperilaku sinkron sehubungan dengan eksekusi yang diblokir. Untuk informasi selengkapnya, lihat https://support.microsoft.com/kb/156932.

 

Meskipun CreateFile adalah fungsi paling umum untuk digunakan untuk membuka file, volume disk, pipa anonim, dan perangkat serupa lainnya, operasi I/O juga dapat dilakukan menggunakan typecast handel dari objek sistem lain seperti soket yang dibuat oleh soket atau menerima fungsi.

Handel ke objek direktori diperoleh dengan memanggil fungsi CreateFile dengan atribut FILE_FLAG_BACKUP_SEMANTICS . Handel direktori hampir tidak pernah digunakan—aplikasi cadangan adalah salah satu dari beberapa aplikasi yang biasanya akan menggunakannya.

Setelah membuka objek file untuk I/O asinkron, struktur yang TUMPANG TINDIH harus dibuat, diinisialisasi, dan diteruskan dengan benar ke setiap panggilan ke fungsi seperti ReadFile dan WriteFile. Ingatlah hal-hal berikut saat menggunakan struktur TUMPANG TINDIH dalam operasi baca dan tulis asinkron:

  • Jangan membatalkan alokasi atau memodifikasi struktur yang TUMPANG TINDIH atau buffer data sampai semua operasi I/O asinkron ke objek file telah selesai.
  • Jika Anda mendeklarasikan pointer Anda ke struktur TUMPANG TINDIH sebagai variabel lokal, jangan keluar dari fungsi lokal sampai semua operasi I/O asinkron ke objek file telah selesai. Jika fungsi lokal keluar sebelum waktunya, struktur TUMPANG TINDIH akan keluar dari cakupan dan tidak akan dapat diakses oleh fungsi ReadFile atau WriteFile yang ditemuinya di luar fungsi itu.

Anda juga dapat membuat peristiwa dan meletakkan handel dalam struktur YANG TUMPANG TINDIH ; fungsi tunggu kemudian dapat digunakan untuk menunggu operasi I/O selesai dengan menunggu handel peristiwa.

Seperti yang dinyatakan sebelumnya, ketika bekerja dengan handel asinkron, aplikasi harus berhati-hati saat membuat penentuan tentang kapan harus membebaskan sumber daya yang terkait dengan operasi I/O tertentu pada handel tersebut. Jika handel dibatalkan alokasinya sebelum waktunya, ReadFile atau WriteFile mungkin salah melaporkan bahwa operasi I/O selesai. Selanjutnya, fungsi WriteFile terkadang akan mengembalikan TRUE dengan nilai GetLastErrorERROR_SUCCESS, meskipun menggunakan handel asinkron (yang juga dapat mengembalikan FALSE dengan ERROR_IO_PENDING). Programmer yang terbiasa dengan desain I/O sinkron biasanya akan merilis sumber daya buffer data pada saat ini karena TRUE dan ERROR_SUCCESS menandakan operasi selesai. Namun, jika port penyelesaian I/O digunakan dengan handel asinkron ini, paket penyelesaian juga akan dikirim meskipun operasi I/O segera selesai. Dengan kata lain, jika aplikasi membebaskan sumber daya setelah WriteFile mengembalikan TRUE dengan ERROR_SUCCESS selain dalam rutinitas port penyelesaian I/O, aplikasi akan memiliki kondisi kesalahan bebas ganda. Dalam contoh ini, rekomendasinya adalah untuk memungkinkan rutinitas port penyelesaian bertanggung jawab sepenuhnya atas semua operasi pengosongan untuk sumber daya tersebut.

Sistem tidak mempertahankan penunjuk file pada handel asinkron ke file dan perangkat yang mendukung penunjuk file (yaitu, mencari perangkat), oleh karena itu posisi file harus diteruskan ke fungsi baca dan tulis dalam anggota data offset terkait dari struktur yang TUMPANG TINDIH . Untuk informasi selengkapnya, lihat WriteFile dan ReadFile.

Posisi penunjuk file untuk handel sinkron dipertahankan oleh sistem saat data dibaca atau ditulis dan juga dapat diperbarui menggunakan fungsi SetFilePointer atau SetFilePointerEx .

Aplikasi juga dapat menunggu handel file untuk menyinkronkan penyelesaian operasi I/O, tetapi melakukannya membutuhkan perhatian ekstrem. Setiap kali operasi I/O dimulai, sistem operasi mengatur handel file ke status tidak ditandatangani. Setiap kali operasi I/O selesai, sistem operasi mengatur handel file ke status yang disinyalkan. Oleh karena itu, jika aplikasi memulai dua operasi I/O dan menunggu pada handel file, tidak ada cara untuk menentukan operasi mana yang selesai ketika handel diatur ke status sinyal. Jika aplikasi harus melakukan beberapa operasi I/O asinkron pada satu file, aplikasi harus menunggu pada handel peristiwa dalam struktur TUMPANG TINDIH tertentu untuk setiap operasi I/O, bukan pada handel file umum.

Untuk membatalkan semua operasi I/O asinkron yang tertunda, gunakan:

  • CancelIo—fungsi ini hanya membatalkan operasi yang dikeluarkan oleh utas panggilan untuk handel file yang ditentukan.
  • CancelIoEx—fungsi ini membatalkan semua operasi yang dikeluarkan oleh utas untuk handel file yang ditentukan.

Gunakan CancelSynchronousIo untuk membatalkan operasi I/O sinkron yang tertunda.

Fungsi ReadFileEx dan WriteFileEx memungkinkan aplikasi menentukan rutinitas untuk dijalankan (lihat FileIOCompletionRoutine) ketika permintaan I/O asinkron selesai.