Apartemen Single-Threaded
Menggunakan apartemen berulir tunggal (proses model apartemen) menawarkan paradigma berbasis pesan untuk menangani beberapa objek yang berjalan bersamaan. Ini memungkinkan Anda menulis kode yang lebih efisien dengan mengizinkan utas, sementara menunggu beberapa operasi yang memakan waktu selesai, untuk memungkinkan utas lain dijalankan.
Setiap utas dalam proses yang diinisialisasi sebagai proses model apartemen, dan yang mengambil dan mengirimkan pesan jendela, adalah utas apartemen berulir tunggal. Setiap utas tinggal di dalam apartemennya sendiri. Dalam apartemen, pointer antarmuka dapat dilewati tanpa marshaling, dan oleh karena itu, semua objek dalam satu utas apartemen berulir tunggal berkomunikasi secara langsung.
Pengelompokan logis objek terkait yang semuanya dijalankan pada utas yang sama, dan oleh karena itu harus memiliki eksekusi sinkron, dapat hidup pada utas apartemen berulir tunggal yang sama. Namun, objek model apartemen tidak dapat berada di lebih dari satu utas. Panggilan ke objek di utas lain harus dilakukan dalam konteks alur pemilik, jadi COM terdistribusi mengalihkan utas untuk Anda secara otomatis saat Anda memanggil pada proksi.
Model interprocess dan interthread serupa. Ketika perlu untuk meneruskan penunjuk antarmuka ke objek di apartemen lain (di utas lain) dalam proses yang sama, Anda menggunakan model marshaling yang sama yang digunakan objek dalam proses yang berbeda untuk melewati penunjuk di seluruh batas proses. Dengan mendapatkan pointer ke objek marshaling standar, Anda dapat marshal penunjuk antarmuka di seluruh batas utas (antar apartemen) dengan cara yang sama seperti yang Anda lakukan di antara proses. (Penunjuk antarmuka harus dinaikkan ketika diteruskan di antara apartemen.)
Aturan untuk apartemen berulir tunggal sederhana, tetapi penting untuk mengikutinya dengan hati-hati:
- Setiap objek harus hidup hanya pada satu utas (dalam satu rangkaian apartemen).
- Inisialisasi pustaka COM untuk setiap utas.
- Marsekal semua pointer ke objek ketika melewati mereka antara apartemen.
- Setiap apartemen berulir tunggal harus memiliki perulangan pesan untuk menangani panggilan dari proses dan apartemen lain dalam proses yang sama. Apartemen berulir tunggal tanpa objek (hanya klien) juga memerlukan perulangan pesan untuk mengirimkan pesan siaran yang digunakan beberapa aplikasi.
- Objek berbasis DLL atau dalam proses tidak memanggil fungsi inisialisasi COM; sebaliknya, mereka mendaftarkan model utas mereka dengan nilai bernama ThreadingModel di bawah kunci InprocServer32 di registri. Objek yang sadar apartemen juga harus menulis titik masuk DLL dengan hati-hati. Ada pertimbangan khusus yang berlaku untuk server utas dalam proses. Untuk informasi selengkapnya, lihat Masalah Utas Server Dalam Proses.
Meskipun beberapa objek dapat hidup di satu utas, tidak ada objek model apartemen yang dapat hidup di lebih dari satu utas.
Setiap alur proses klien atau server di luar proses harus memanggil CoInitialize, atau memanggil CoInitializeEx dan menentukan COINIT_APARTMENTTHREADED untuk parameter dwCoInit. Apartemen utama adalah utas yang memanggil CoInitializeEx terlebih dahulu. Untuk informasi tentang server dalam proses, lihat Masalah Utas Server Dalam Proses.
Semua panggilan ke objek harus dilakukan pada utasnya (di dalam apartemennya). Dilarang memanggil objek langsung dari utas lain; menggunakan objek dengan cara berulir bebas ini dapat menyebabkan masalah untuk aplikasi. Implikasi dari aturan ini adalah bahwa semua penunjuk ke objek harus dirusak ketika diteruskan di antara apartemen. COM menyediakan dua fungsi berikut untuk tujuan ini:
- CoMarshalInterThreadInterfaceInStream melakukan marshal antarmuka ke dalam objek aliran yang dikembalikan ke pemanggil.
- CoGetInterfaceAndReleaseStream membatalkan nama penunjuk antarmuka dari objek aliran dan merilisnya.
Fungsi-fungsi ini membungkus panggilan ke fungsi CoMarshalInterface dan CoUnmarshalInterface, yang memerlukan penggunaan bendera MSHCTX_INPROC.
Secara umum, marshaling dilakukan secara otomatis oleh COM. Misalnya, saat meneruskan pointer antarmuka sebagai parameter dalam panggilan metode pada proksi ke objek di apartemen lain, atau saat memanggil CoCreateInstance, COM melakukan marshaling secara otomatis. Namun, dalam beberapa kasus khusus, di mana penulis aplikasi melewati penunjuk antarmuka antara apartemen tanpa menggunakan mekanisme COM normal, penulis harus menangani marshaling secara manual.
Jika satu apartemen (Apartemen 1) dalam proses memiliki penunjuk antarmuka dan apartemen lain (Apartemen 2) memerlukan penggunaannya, Apartemen 1 harus memanggil CoMarshalInterThreadInStream untuk melakukan marshal antarmuka. Aliran yang dibuat oleh fungsi ini aman utas dan harus disimpan dalam variabel yang dapat diakses oleh Apartemen 2. Apartemen 2 harus meneruskan aliran ini ke CoGetInterfaceAndReleaseStream untuk membatalkan nama antarmuka dan akan mengembalikan pointer ke proksi tempat ia dapat mengakses antarmuka. Apartemen utama harus tetap hidup sampai klien menyelesaikan semua pekerjaan COM (karena beberapa objek dalam proses dimuat di apartemen utama, seperti yang dijelaskan dalam Masalah Threading Server Dalam Proses). Setelah satu objek diteruskan di antara utas dengan cara ini, sangat mudah untuk meneruskan penunjuk antarmuka sebagai parameter. Dengan begitu, COM terdistribusi melakukan peralihan marshaling dan utas untuk aplikasi.
Untuk menangani panggilan dari proses dan apartemen lain dalam proses yang sama, setiap apartemen berulir tunggal harus memiliki perulangan pesan. Ini berarti bahwa fungsi kerja utas harus memiliki perulangan GetMessage/DispatchMessage. Jika primitif sinkronisasi lainnya digunakan untuk berkomunikasi antar alur, fungsi MsgWaitForMultipleObjects dapat digunakan untuk menunggu pesan dan untuk peristiwa sinkronisasi utas. Dokumentasi untuk fungsi ini memiliki contoh perulangan kombinasi semacam ini.
COM membuat jendela tersembunyi menggunakan kelas Windows "OleMainThreadWndClass" di setiap apartemen berulir tunggal. Panggilan ke objek diterima sebagai pesan jendela ke jendela tersembunyi ini. Ketika apartemen objek mengambil dan mengirimkan pesan, jendela tersembunyi akan menerimanya. Prosedur jendela kemudian akan memanggil metode antarmuka objek yang sesuai.
Ketika beberapa klien memanggil objek, panggilan diantrekan dalam antrean pesan dan objek akan menerima panggilan setiap kali apartemennya mengambil dan mengirimkan pesan. Karena panggilan disinkronkan oleh COM dan panggilan selalu dikirimkan oleh utas milik apartemen objek, implementasi antarmuka objek tidak perlu memberikan sinkronisasi. Apartemen berulir tunggal dapat mengimplementasikan IMessageFilter untuk mengizinkan mereka membatalkan panggilan atau menerima pesan jendela bila perlu.
Objek dapat dimasukkan kembali jika salah satu implementasi metode antarmukanya mengambil dan mengirim pesan atau melakukan panggilan ORPC ke utas lain, sehingga menyebabkan panggilan lain dikirimkan ke objek (oleh apartemen yang sama). OLE tidak mencegah masuknya kembali pada utas yang sama, tetapi dapat membantu memberikan keamanan utas. Ini identik dengan cara di mana prosedur jendela dapat dimasukkan kembali jika mengambil dan mengirimkan pesan saat memproses pesan. Namun, memanggil server apartemen berulir tunggal di luar proses yang memanggil server apartemen utas tunggal lainnya akan memungkinkan server pertama untuk masuk kembali.
Topik terkait