Bagikan melalui


Inisialisasi One-Time

Komponen sering dirancang untuk melakukan tugas inisialisasi ketika pertama kali dipanggil, bukan ketika dimuat. Fungsi inisialisasi satu kali memastikan bahwa inisialisasi ini hanya terjadi sekali, bahkan ketika beberapa utas dapat mencoba inisialisasi.

Windows Server 2003 dan Windows XP: aplikasi harus menyediakan sinkronisasi mereka sendiri untuk inisialisasi satu kali dengan menggunakan fungsi yang saling mengunci atau mekanisme sinkronisasi lainnya. Fungsi inisialisasi satu kali tersedia dimulai dengan Windows Vista dan Windows Server 2008.

Fungsi inisialisasi satu kali memberikan keuntungan signifikan untuk memastikan bahwa hanya satu utas yang melakukan inisialisasi:

  • Mereka dioptimalkan untuk kecepatan.
  • Mereka menciptakan hambatan yang sesuai pada arsitektur prosesor yang memerlukannya.
  • Mereka mendukung inisialisasi terkunci dan paralel.
  • Mereka menghindari penguncian internal sehingga kode dapat beroperasi secara asinkron atau sinkron.

Sistem mengelola proses inisialisasi melalui struktur INIT_ONCE buram yang berisi data dan informasi status. Pemanggil mengalokasikan struktur ini dan menginisialisasinya dengan memanggil InitOnceInitialize (untuk menginisialisasi struktur secara dinamis) atau menetapkan konstanta INIT_ONCE_STATIC_INIT ke variabel struktur (untuk menginisialisasi struktur secara statis). Awalnya, data yang disimpan dalam struktur inisialisasi satu kali adalah NULL dan statusnya tidak diinisialisasi.

Struktur inisialisasi satu kali tidak dapat dibagikan di seluruh proses.

Utas yang melakukan inisialisasi dapat secara opsional mengatur konteks yang tersedia untuk pemanggil setelah inisialisasi selesai. Konteksnya bisa menjadi objek sinkronisasi atau bisa berupa nilai atau struktur data. Jika konteks adalah nilai, INIT_ONCE_CTX_RESERVED_BITS berurutan rendah harus nol. Jika konteksnya adalah struktur data, struktur data harus DWORD-aligned. Konteks dikembalikan ke pemanggil dalam parameter output lpContext dari InitOnceBeginInitialize atau fungsi InitOnceExecuteOnce.

Inisialisasi satu kali dapat dilakukan secara sinkron atau asinkron. Fungsi panggilan balik opsional dapat digunakan untuk inisialisasi satu kali yang sinkron.

Inisialisasi Satu Kali Sinkron

Langkah-langkah berikut menjelaskan inisialisasi satu kali sinkron yang tidak menggunakan fungsi panggilan balik.

  1. Utas pertama yang memanggil fungsi InitOnceBeginInitialize berhasil menyebabkan inisialisasi satu kali dimulai. Untuk inisialisasi satu kali sinkron, InitOnceBeginInitialize harus dipanggil tanpa bendera INIT_ONCE_ASYNC.
  2. Alur berikutnya yang mencoba inisialisasi diblokir hingga utas pertama menyelesaikan inisialisasi atau gagal. Jika utas pertama gagal, utas berikutnya diizinkan untuk mencoba inisialisasi, dan sebagainya.
  3. Setelah inisialisasi selesai, utas memanggil fungsiInitOnceComplete. Utas dapat secara opsional membuat objek sinkronisasi (atau data konteks lainnya) dan menentukannya dalam parameter lpContext dari fungsi initOnceComplete.
  4. Jika inisialisasi berhasil, status struktur inisialisasi satu kali diubah menjadi diinisialisasi dan lpContext handel (jika ada) disimpan dalam struktur inisialisasi. Upaya inisialisasi berikutnya mengembalikan data konteks ini. Jika inisialisasi gagal, data NULL.

Langkah-langkah berikut menjelaskan inisialisasi satu kali sinkron yang menggunakan fungsi panggilan balik.

  1. Alur pertama yang berhasil memanggil fungsiInitOnceExecuteOnce meneruskan penunjuk ke fungsi panggilan balik InitOnceCallback yang ditentukan aplikasi dan data apa pun yang diperlukan oleh fungsi panggilan balik. Jika panggilan berhasil, fungsi panggilan balik InitOnceCallback dijalankan.
  2. Alur berikutnya yang mencoba inisialisasi diblokir hingga utas pertama menyelesaikan inisialisasi atau gagal. Jika utas pertama gagal, utas berikutnya diizinkan untuk mencoba inisialisasi, dan sebagainya.
  3. Setelah inisialisasi selesai, fungsi panggilan balik akan kembali. Fungsi panggilan balik dapat secara opsional membuat objek sinkronisasi (atau data konteks lainnya) dan menentukannya dalam parameter output Konteks.
  4. Jika inisialisasi berhasil, status struktur inisialisasi satu kali diubah menjadi diinisialisasi dan handel Konteks (jika ada) disimpan dalam struktur inisialisasi. Upaya inisialisasi berikutnya mengembalikan data konteks ini. Jika inisialisasi gagal, data NULL.

Inisialisasi Satu Kali Asinkron

Langkah-langkah berikut menjelaskan inisialisasi satu kali asinkron.

  1. Jika beberapa utas secara bersamaan mencoba memulai inisialisasi dengan memanggil InitOnceBeginInitialize dengan INIT_ONCE_ASYNC, fungsi berhasil untuk semua utas dengan parameter fPending diatur ke TRUE. Hanya satu utas yang benar-benar akan berhasil saat inisialisasi; upaya bersamaan lainnya tidak mengubah status inisialisasi.
  2. Saat InitOnceBeginInitialize kembali, parameter fPending menunjukkan status inisialisasi:
    • Jika fPending FALSE, satu utas telah berhasil pada inisialisasi. Utas lain harus membersihkan data konteks apa pun yang telah mereka buat dan menggunakan data konteks dalam parameter output lpContextInitOnceBeginInitialize.
    • Jika fPending TRUE, inisialisasi belum selesai dan utas lainnya harus dilanjutkan.
  3. Setiap utas memanggil fungsiinitOnceComplete. Utas dapat secara opsional membuat objek sinkronisasi (atau data konteks lainnya) dan menentukannya di parameter lpContext InitOnceComplete.
  4. Saat InitOnceComplete kembali, nilai pengembaliannya menunjukkan apakah utas panggilan berhasil pada inisialisasi.
    • Jika InitOnceComplete berhasil, utas panggilan telah berhasil pada inisialisasi. Status struktur inisialisasi satu kali diubah menjadi diinisialisasi dan handel lpContext (jika ada) disimpan dalam struktur inisialisasi.
    • Jika InitOnceComplete gagal, utas lain telah berhasil pada inisialisasi. Utas panggilan harus membersihkan data konteks apa pun yang telah dibuatnya dan memanggil InitOnceBeginInitialize dengan INIT_ONCE_CHECK_ONLY untuk mengambil data konteks apa pun yang disimpan dalam struktur inisialisasi satu kali.

Memanggil Inisialisasi One-Time dari beberapa situs

Inisialisasi satu kali yang dijaga oleh struktur INIT_ONCE tunggal dapat dilakukan dari beberapa situs; panggilan balik yang berbeda dapat diteruskan dari setiap situs, dan sinkronisasi dengan dan tanpa panggilan balik dapat dicampur. Inisialisasi masih dijamin berhasil dilakukan hanya sekali.

Namun, inisialisasi asinkron dan sinkron tidak dapat dicampur: setelah inisialisasi asinkron dicoba, upaya untuk memulai inisialisasi sinkron akan gagal.

Menggunakan Inisialisasi One-Time