Port Penyelesaian I/O

Port penyelesaian I/O menyediakan model utas yang efisien untuk memproses beberapa permintaan I/O asinkron pada sistem multiprosesor. Ketika proses membuat port penyelesaian I/O, sistem membuat objek antrean terkait untuk utas yang tujuan tunggalnya adalah untuk melayani permintaan ini. Proses yang menangani banyak permintaan I/O asinkron bersamaan dapat melakukannya lebih cepat dan efisien dengan menggunakan port penyelesaian I/O bersama dengan kumpulan utas yang telah dialokasikan sebelumnya daripada dengan membuat utas pada saat mereka menerima permintaan I/O.

Cara Kerja Port Penyelesaian I/O

Fungsi CreateIoCompletionPort membuat port penyelesaian I/O dan mengaitkan satu atau beberapa handel file dengan port tersebut. Ketika operasi I/O asinkron pada salah satu handel file ini selesai, paket penyelesaian I/O diantrekan dalam urutan first-in-first-out (FIFO) ke port penyelesaian I/O terkait. Salah satu penggunaan yang kuat untuk mekanisme ini adalah menggabungkan titik sinkronisasi untuk beberapa handel file ke dalam satu objek, meskipun ada juga aplikasi berguna lainnya. Harap dicatat bahwa saat paket diantrekan dalam urutan FIFO, paket tersebut mungkin di-dequeu dalam urutan yang berbeda.

Catatan

Istilah handel file seperti yang digunakan di sini mengacu pada abstraksi sistem yang mewakili titik akhir I/O yang tumpang tindih, tidak hanya file pada disk. Misalnya, itu bisa menjadi titik akhir jaringan, soket TCP, pipa bernama, atau slot email. Objek sistem apa pun yang mendukung I/O yang tumpang tindih dapat digunakan. Untuk daftar fungsi I/O terkait, lihat akhir topik ini.

 

Ketika handel file dikaitkan dengan port penyelesaian, blok status yang diteruskan tidak akan diperbarui sampai paket dihapus dari port penyelesaian. Satu-satunya pengecualian adalah jika operasi asli kembali secara sinkron dengan kesalahan. Utas (baik yang dibuat oleh utas utama atau utas utama itu sendiri) menggunakan fungsi GetQueuedCompletionStatus untuk menunggu paket penyelesaian diantrekan ke port penyelesaian I/O, daripada menunggu langsung I/O asinkron selesai. Utas yang memblokir eksekusinya pada port penyelesaian I/O dirilis dalam urutan last-in-first-out (LIFO), dan paket penyelesaian berikutnya ditarik dari antrean FIFO port penyelesaian I/O untuk utas tersebut. Ini berarti bahwa, ketika paket penyelesaian dirilis ke utas, sistem merilis utas terakhir (terbaru) yang terkait dengan port tersebut, meneruskannya informasi penyelesaian untuk penyelesaian I/O tertua.

Meskipun sejumlah utas dapat memanggil GetQueuedCompletionStatus untuk port penyelesaian I/O tertentu, ketika utas tertentu memanggil GetQueuedCompletionStatus untuk pertama kalinya, alur tersebut akan dikaitkan dengan port penyelesaian I/O yang ditentukan hingga salah satu dari tiga hal terjadi: Alur keluar, menentukan port penyelesaian I/O yang berbeda, atau menutup port penyelesaian I/O. Dengan kata lain, satu utas dapat dikaitkan dengan, paling banyak, satu port penyelesaian I/O.

Ketika paket penyelesaian diantrekan ke port penyelesaian I/O, sistem terlebih dahulu memeriksa berapa banyak utas yang terkait dengan port tersebut yang berjalan. Jika jumlah utas yang berjalan kurang dari nilai konkurensi (dibahas di bagian berikutnya), salah satu utas tunggu (yang terbaru) diizinkan untuk memproses paket penyelesaian. Ketika utas yang sedang berjalan menyelesaikan pemrosesannya, biasanya memanggil GetQueuedCompletionStatus lagi, di mana ia kembali dengan paket penyelesaian berikutnya atau menunggu jika antrean kosong.

Utas dapat menggunakan fungsi PostQueuedCompletionStatus untuk menempatkan paket penyelesaian dalam antrean port penyelesaian I/O. Dengan demikian, port penyelesaian dapat digunakan untuk menerima komunikasi dari utas proses lainnya, selain menerima paket penyelesaian I/O dari sistem I/O. Fungsi PostQueuedCompletionStatus memungkinkan aplikasi untuk mengantre paket penyelesaian tujuan khususnya sendiri ke port penyelesaian I/O tanpa memulai operasi I/O asinkron. Ini berguna untuk memberi tahu utas pekerja tentang peristiwa eksternal, misalnya.

Handel port penyelesaian I/O dan setiap handel file yang terkait dengan port penyelesaian I/O tertentu dikenal sebagai referensi ke port penyelesaian I/O. Port penyelesaian I/O dirilis ketika tidak ada lagi referensi untuk itu. Oleh karena itu, semua handel ini harus ditutup dengan benar untuk merilis port penyelesaian I/O dan sumber daya sistem terkait. Setelah kondisi ini terpenuhi, aplikasi harus menutup handel port penyelesaian I/O dengan memanggil fungsi CloseHandle .

Catatan

Port penyelesaian I/O dikaitkan dengan proses yang membuatnya dan tidak dapat dibagi di antara proses. Namun, satu handel dapat dibagi antara utas dalam proses yang sama.

 

Utas dan Konkurensi

Properti terpenting dari port penyelesaian I/O untuk dipertimbangkan dengan hati-hati adalah nilai konkurensi. Nilai konkurensi port penyelesaian ditentukan ketika dibuat dengan CreateIoCompletionPort melalui parameter NumberOfConcurrentThreads . Nilai ini membatasi jumlah utas yang dapat dijalankan yang terkait dengan port penyelesaian. Ketika jumlah total utas yang dapat dijalankan yang terkait dengan port penyelesaian mencapai nilai konkurensi, sistem memblokir eksekusi utas berikutnya yang terkait dengan port penyelesaian tersebut hingga jumlah utas yang dapat dijalankan turun di bawah nilai konkurensi.

Skenario paling efisien terjadi ketika ada paket penyelesaian yang menunggu dalam antrean, tetapi tidak ada penantian yang dapat dipenuhi karena port telah mencapai batas konkurensinya. Pertimbangkan apa yang terjadi dengan nilai konkurensi satu dan beberapa utas yang menunggu dalam panggilan fungsi GetQueuedCompletionStatus . Dalam hal ini, jika antrean selalu memiliki paket penyelesaian yang menunggu, ketika utas yang berjalan memanggil GetQueuedCompletionStatus, antrean tidak akan memblokir eksekusi karena, seperti yang disebutkan sebelumnya, antrean utas adalah LIFO. Sebagai gantinya, utas ini akan segera mengambil paket penyelesaian antrean berikutnya. Tidak ada sakelar konteks utas yang akan terjadi, karena utas yang sedang berjalan terus mengambil paket penyelesaian dan utas lainnya tidak dapat dijalankan.

Catatan

Dalam contoh sebelumnya, utas tambahan tampaknya tidak berguna dan tidak pernah berjalan, tetapi itu mengasumsikan bahwa utas yang berjalan tidak pernah dimasukkan ke dalam status tunggu oleh beberapa mekanisme lain, mengakhiri, atau menutup port penyelesaian I/O terkait. Pertimbangkan semua ramifikasi eksekusi utas tersebut saat merancang aplikasi.

 

Nilai maksimum keseluruhan terbaik yang harus dipilih untuk nilai konkurensi adalah jumlah CPU di komputer. Jika transaksi Anda memerlukan komputasi yang panjang, nilai konkurensi yang lebih besar akan memungkinkan lebih banyak utas berjalan. Setiap paket penyelesaian mungkin membutuhkan waktu lebih lama untuk diselesaikan, tetapi lebih banyak paket penyelesaian akan diproses secara bersamaan. Anda dapat bereksperimen dengan nilai konkurensi bersama dengan alat pembuatan profil untuk mencapai efek terbaik untuk aplikasi Anda.

Sistem ini juga memungkinkan utas yang menunggu di GetQueuedCompletionStatus untuk memproses paket penyelesaian jika utas lain yang berjalan yang terkait dengan port penyelesaian I/O yang sama memasuki status tunggu karena alasan lain, misalnya fungsi SuspendThread . Ketika utas dalam status tunggu mulai berjalan lagi, mungkin ada periode singkat ketika jumlah utas aktif melebihi nilai konkurensi. Namun, sistem dengan cepat mengurangi angka ini dengan tidak mengizinkan utas aktif baru hingga jumlah utas aktif berada di bawah nilai konkurensi. Ini adalah salah satu alasan agar aplikasi Anda membuat lebih banyak utas di kumpulan utasnya daripada nilai konkurensi. Manajemen kumpulan utas berada di luar cakupan topik ini, tetapi aturan praktis yang baik adalah memiliki minimal dua kali lebih banyak utas di kumpulan utas karena ada prosesor pada sistem. Untuk informasi tambahan tentang pengumpulan utas, lihat Kumpulan Utas.

Fungsi I/O yang Didukung

Fungsi berikut dapat digunakan untuk memulai operasi I/O yang selesai dengan menggunakan port penyelesaian I/O. Anda harus meneruskan fungsi instans struktur TUMPANG TINDIH dan handel file yang sebelumnya terkait dengan port penyelesaian I/O (dengan panggilan ke CreateIoCompletionPort) untuk mengaktifkan mekanisme port penyelesaian I/O:

Tentang Proses dan Utas

BindIoCompletionCallback

CreateIoCompletionPort

GetQueuedCompletionStatus

GetQueuedCompletionStatusEx

PostQueuedCompletionStatus