Bagikan melalui


Penjadwalan User-Mode

Peringatan

Pada Windows 11, penjadwalan mode pengguna tidak didukung. Semua panggilan gagal dengan kesalahan ERROR_NOT_SUPPORTED.

Penjadwalan di tingkat pengguna (UMS) adalah mekanisme ringan yang dapat digunakan aplikasi untuk menjadwalkan utas mereka sendiri. Aplikasi dapat beralih antara utas UMS dalam mode pengguna tanpa melibatkan penjadwal sistem dan mendapatkan kembali kontrol prosesor jika utas UMS diblokir di kernel. Utas UMS berbeda dari serat dalam hal bahwa setiap utas UMS memiliki konteks utasnya sendiri, bukan berbagi konteks utas dari satu utas saja. Kemampuan untuk beralih antar utas dalam mode pengguna memungkinkan UMS lebih efisien daripada kumpulan utas untuk mengelola sejumlah besar item kerja berdurasi pendek yang memerlukan sedikit panggilan sistem.

UMS direkomendasikan untuk aplikasi dengan persyaratan performa tinggi yang perlu menjalankan banyak utas secara efisien secara bersamaan pada sistem multiprosedur atau multicore. Untuk memanfaatkan UMS, aplikasi harus menerapkan komponen penjadwal yang mengelola utas UMS aplikasi dan menentukan kapan mereka harus berjalan. Pengembang harus mempertimbangkan apakah persyaratan performa aplikasi mereka membenarkan pekerjaan yang terlibat dalam mengembangkan komponen tersebut. Aplikasi dengan persyaratan performa sedang mungkin lebih baik dilayani dengan memungkinkan penjadwal sistem untuk menjadwalkan utas mereka.

UMS tersedia untuk aplikasi 64-bit yang berjalan pada versi AMD64 dan Itanium Windows 7 dan Windows Server 2008 R2 hingga Windows 10 Versi 21H2 dan Windows Server 2022. Fitur ini tidak tersedia di Windows versi Arm64, 32-bit atau pada Windows 11.

Untuk detailnya, lihat bagian berikut ini:

Penjadwal UMS

Penjadwal UMS aplikasi bertanggung jawab untuk membuat, mengelola, dan menghapus utas UMS dan menentukan utas UMS mana yang akan dijalankan. Penjadwal aplikasi melakukan tugas-tugas berikut:

  • Membuat satu utas penjadwal UMS untuk setiap prosesor tempat aplikasi akan menjalankan utas pekerja UMS.
  • Membuat thread pekerja UMS untuk menjalankan pekerjaan aplikasi.
  • Mengelola antrian utas siap mandiri dari utas pekerja yang siap dijalankan, dan menentukan utas mana yang akan dijalankan berdasarkan kebijakan penjadwalan aplikasi.
  • Membuat dan memantau satu atau beberapa daftar penyelesaian tempat sistem mengantre utas setelah selesai diproses di kernel. Ini termasuk utas pekerja yang baru dibuat dan utas lain yang sebelumnya diblokir pada panggilan sistem yang menjadi tidak diblokir.
  • Menyediakan fungsi titik masuk penjadwal untuk menangani pemberitahuan dari sistem. Sistem memanggil fungsi titik masuk saat utas penjadwal dibuat, utas pekerja memblokir panggilan sistem, atau utas pekerja secara eksplisit menghasilkan kontrol.
  • Melakukan tugas pembersihan untuk utas pekerja yang telah selesai beroperasi.
  • Melakukan penonaktifan penjadwal secara teratur saat diminta oleh aplikasi.

Utas Penjadwalan UMS

Utas penjadwal UMS adalah utas biasa yang telah dikonversi ke UMS dengan memanggil fungsi EnterUmsSchedulingMode. Penjadwal sistem menentukan kapan utas penjadwal UMS berjalan berdasarkan prioritasnya relatif terhadap utas siap lainnya. Prosesor tempat utas penjadwal berjalan dipengaruhi oleh afinitas utas, sama seperti untuk utas non-UMS.

Pemanggil EnterUmsSchedulingMode menentukan daftar penyelesaian dan fungsi titik masuk UmsSchedulerProc untuk dikaitkan dengan utas penjadwal UMS. Sistem memanggil fungsi titik masuk yang ditentukan ketika selesai mengonversi utas panggilan ke UMS. Fungsi titik masuk penjadwal bertanggung jawab untuk menentukan tindakan berikutnya yang sesuai untuk utas yang ditentukan. Untuk informasi selengkapnya, lihat Fungsi Titik Masuk Penjadwal UMS nanti dalam topik ini.

Aplikasi mungkin membuat satu utas penjadwal UMS untuk setiap prosesor yang akan digunakan untuk menjalankan utas UMS. Aplikasi ini mungkin juga mengatur afinitas setiap utas penjadwal UMS untuk prosesor logis tertentu, yang cenderung menghindarkan utas yang tidak terkait agar tidak berjalan di prosesor itu, sebagai bentuk reservasi untuk utas penjadwal tersebut. Ketahuilah bahwa mengatur afinitas utas dengan cara ini dapat memengaruhi performa sistem secara keseluruhan dengan mengabaikan proses lain yang mungkin sedang berjalan pada sistem. Untuk informasi selengkapnya tentang afinitas utas, lihat Beberapa Prosesor.

Utas Pekerja UMS, Konteks Utas, dan Daftar Penyelesaian

Utas pekerja UMS dibuat dengan memanggil CreateRemoteThreadEx dengan atribut PROC_THREAD_ATTRIBUTE_UMS_THREAD dan menentukan konteks utas UMS dan daftar penyelesaian.

Konteks utas UMS mewakili status utas UMS dari utas pekerja dan digunakan untuk mengidentifikasi utas pekerja dalam panggilan fungsi UMS. Ini dibuat dengan memanggil CreateUmsThreadContext.

Daftar penyelesaian dibuat dengan memanggil fungsiCreateUmsCompletionList. Daftar penyelesaian menerima utas pekerja UMS yang telah menyelesaikan eksekusi di kernel dan siap beroperasi dalam mode pengguna. Hanya sistem yang dapat mengantrikan utas pekerja ke daftar penyelesaian. Utas pekerja baru UMS secara otomatis diantrekan ke daftar penyelesaian yang ditentukan saat utas tersebut dibuat. Thread pekerja yang sebelumnya diblokir juga masuk dalam antrean ke daftar penyelesaian ketika tidak lagi diblokir.

Setiap thread penjadwal UMS terhubung dengan satu daftar penyelesaian. Namun, daftar penyelesaian tugas yang sama dapat dikaitkan dengan sejumlah utas penjadwal UMS, dan utas penjadwal dapat mengambil konteks UMS dari daftar penyelesaian tugas mana pun untuk mana ia memiliki penunjuk.

Setiap daftar penyelesaian memiliki peristiwa terkait yang disinyalir oleh sistem saat mengantrekan satu atau beberapa utas pekerja ke daftar kosong. Fungsi GetUmsCompletionListEvent mengambil alih handle ke event untuk daftar penyelesaian yang ditentukan. Aplikasi dapat menunggu lebih dari satu acara daftar penyelesaian tugas bersama dengan acara lain yang relevan untuk aplikasi.

Fungsi Titik Masuk Penjadwal UMS

Fungsi titik masuk penjadwal untuk aplikasi diimplementasikan sebagai fungsi UmsSchedulerProc. Sistem memanggil fungsi titik masuk penjadwal aplikasi pada waktu berikut:

  • Saat sebuah utas non-UMS dikonversi menjadi utas penjadwal UMS dengan memanggil EnterUmsSchedulingMode.
  • Ketika utas pekerja UMS memanggil UmsThreadYield.
  • Saat utas pekerja UMS memblokir layanan sistem seperti panggilan sistem atau kesalahan halaman.

Parameter Reason fungsi UmsSchedulerProc menentukan alasan fungsi titik masuk dipanggil. Jika fungsi titik masuk dipanggil karena utas penjadwal UMS baru dibuat, parameter SchedulerParam mengandung data yang ditentukan oleh pemanggil EnterUmsSchedulingMode. Jika fungsi titik masuk dipanggil karena utas pekerja UMS dihasilkan, parameter SchedulerParam berisi data yang ditentukan oleh pemanggil UmsThreadYield. Jika fungsi titik masuk dipanggil karena utas pekerja UMS mengalami pemblokiran di kernel, parameter SchedulerParam adalah NULL.

Fungsi titik masuk penjadwal bertanggung jawab untuk menentukan tindakan berikutnya yang sesuai untuk utas yang ditentukan. Misalnya, jika utas pekerja diblokir, fungsi titik masuk penjadwal tugas mungkin menjalankan utas pekerja UMS siap yang tersedia berikutnya.

Ketika fungsi titik masuk penjadwal dipanggil, penjadwal aplikasi harus mencoba mengambil semua item dalam daftar penyelesaian terkait dengan memanggil fungsi DequeueUmsCompletionListItems. Fungsi ini mengambil daftar konteks utas UMS yang telah selesai diproses di kernel dan siap dijalankan dalam mode pengguna. Penjadwal aplikasi tidak boleh menjalankan utas UMS langsung dari daftar ini karena ini dapat menyebabkan perilaku yang tidak dapat diprediksi dalam aplikasi. Sebagai gantinya, penjadwal harus mengambil semua konteks utas UMS dengan memanggil fungsi GetNextUmsListItem sekali untuk setiap konteks, memasukkan konteks utas UMS ke dalam antrean utas siap penjadwal, dan hanya kemudian menjalankan utas UMS dari antrean utas siap tersebut.

Jika penjadwal tidak perlu menunggu beberapa peristiwa, penjadwal harus memanggil DequeueUmsCompletionListItems dengan parameter batas waktu nonzero sehingga fungsi menunggu peristiwa daftar penyelesaian sebelum kembali. Jika penjadwal memang perlu menunggu beberapa peristiwa daftar penyelesaian, penjadwal harus memanggil DequeueUmsCompletionListItems dengan parameter batas waktu nol sehingga fungsi segera kembali, bahkan jika daftar penyelesaian kosong. Dalam hal ini, penjadwal dapat secara eksplisit menunggu peristiwa di daftar penyelesaian, misalnya, dengan menggunakan WaitForMultipleObjects.

Eksekusi Utas UMS

Utas pekerja UMS yang baru dibuat diantrekan ke daftar penyelesaian yang ditentukan dan tidak mulai berjalan hingga penjadwal UMS aplikasi memilihnya untuk dijalankan. Ini berbeda dari utas non-UMS, yang penjadwal sistemnya secara otomatis menjadwalkan untuk dijalankan, kecuali jika si pemanggil secara eksplisit membuat utas tersebut dalam keadaan ditangguhkan.

Penjadwal menjalankan utas pekerja dengan memanggil ExecuteUmsThread dengan konteks UMS utas pekerja. Utas pekerja UMS berjalan sampai menghasilkan dengan memanggil fungsi, blok, atau penghentian UmsThreadYield.

Praktik Terbaik UMS

Aplikasi yang menerapkan UMS harus mengikuti praktik terbaik berikut:

  • Struktur yang mendasar untuk konteks utas UMS dikelola oleh sistem dan tidak boleh dimodifikasi secara langsung. Sebagai gantinya, gunakan QueryUmsThreadInformation dan SetUmsThreadInformation untuk mengambil dan mengatur informasi tentang utas pekerja UMS.
  • Untuk membantu mencegah kebuntuan, utas penjadwal UMS tidak boleh berbagi kunci dengan utas pekerja UMS. Ini termasuk kunci yang dibuat aplikasi dan kunci sistem yang diperoleh secara tidak langsung oleh operasi seperti mengalokasikan dari timbunan atau memuat DLL. Misalnya, penjadwal menjalankan utas kerja UMS yang memuat DLL. Utas pekerja memperoleh kunci dan blok pemuat. Sistem memanggil fungsi entri penjadwal, yang kemudian memuat DLL. Ini menyebabkan kebuntuan, karena kunci pemuat sudah dipegang dan tidak dapat dilepaskan sampai utas pertama dibuka. Untuk membantu menghindari masalah ini, delegasikan pekerjaan yang mungkin berbagi kunci dengan utas pekerja UMS ke utas pekerja UMS khusus atau utas non-UMS.
  • UMS paling efisien ketika sebagian besar pemrosesan dilakukan dalam mode pengguna. Jika memungkinkan, hindari melakukan panggilan sistem di utas pekerja UMS.
  • Utas pekerja UMS tidak boleh mengasumsikan penjadwal sistem sedang digunakan. Asumsi ini dapat memiliki efek yang tidak terlalu terlihat; misalnya, jika utas dalam kode yang tidak dikenal menetapkan prioritas atau afinitas utas, penjadwal UMS mungkin masih mengabaikannya. Kode yang mengasumsikan penjadwal sistem sedang digunakan mungkin tidak berperilaku seperti yang diharapkan dan dapat rusak ketika dipanggil oleh utas UMS.
  • Sistem mungkin perlu mengunci konteks thread pekerja UMS. Misalnya, panggilan prosedur asinkron (APC) mode kernel dapat mengubah konteks utas UMS, sehingga konteks utas harus dikunci. Jika penjadwal mencoba menjalankan konteks utas UMS saat dikunci, panggilan akan gagal. Perilaku ini memang dirancang seperti itu, dan penjadwal harus diatur untuk mencoba kembali mengakses konteks utas UMS.