Threading dan Marshaling (C++/CX)

Dalam sebagian besar kasus, instans kelas Windows Runtime, seperti objek C++ standar, dapat diakses dari utas apa pun. Kelas seperti itu disebut sebagai "tangkas". Namun, sejumlah kecil kelas Windows Runtime yang dikirim dengan Windows tidak gesit, dan harus dikonsumsi lebih seperti objek COM daripada objek C++ standar. Anda tidak perlu menjadi pakar COM untuk menggunakan kelas non-tangkas, tetapi Anda perlu mempertimbangkan model utas kelas dan perilaku marshaling-nya. Artikel ini menyediakan latar belakang dan panduan untuk skenario langka di mana Anda perlu menggunakan instans kelas non-tangkas.

Model threading dan perilaku marshaling

Kelas Windows Runtime dapat mendukung akses utas bersamaan dengan berbagai cara, seperti yang ditunjukkan oleh dua atribut yang diterapkan padanya:

  • ThreadingModel atribut dapat memiliki salah satu nilai—STA, MTA, atau Keduanya, seperti yang ThreadingModel didefinisikan oleh enumerasi.

  • MarshallingBehavior atribut dapat memiliki salah satu nilai—Agile, None, atau Standard seperti yang MarshallingType didefinisikan oleh enumerasi.

Atribut ThreadingModel menentukan tempat kelas dimuat saat diaktifkan: hanya dalam konteks utas antarmuka pengguna (STA), hanya dalam konteks utas latar belakang (MTA), atau dalam konteks utas yang membuat objek (Keduanya). Nilai MarshallingBehavior atribut mengacu pada bagaimana objek berperilaku dalam berbagai konteks utas; dalam kebanyakan kasus, Anda tidak perlu memahami nilai-nilai ini secara rinci. Dari kelas yang disediakan oleh Windows API, sekitar 90 persen memiliki ThreadingModel=Keduanya dan MarshallingType=Agile. Ini berarti bahwa mereka dapat menangani detail utas tingkat rendah secara transparan dan efisien. Saat Anda menggunakan ref new untuk membuat kelas "tangkas", Anda dapat memanggil metode di dalamnya dari utas aplikasi utama Anda atau dari satu atau beberapa utas pekerja. Dengan kata lain, Anda dapat menggunakan kelas tangkas—tidak peduli apakah kelas tersebut disediakan oleh Windows atau oleh pihak ketiga—dari mana saja dalam kode Anda. Anda tidak perlu khawatir dengan model utas kelas atau perilaku marshaling.

Mengonsumsi komponen Windows Runtime

Saat membuat aplikasi Platform Windows Universal, Anda mungkin berinteraksi dengan komponen tangkas dan non-tangkas. Saat berinteraksi dengan komponen non-tangkas, Anda mungkin mengalami peringatan berikut.

Compiler memperingatkan C4451 saat menggunakan kelas non-agile

Karena berbagai alasan, beberapa kelas tidak bisa gesar. Jika Anda mengakses instans kelas non-tangkas dari utas antarmuka pengguna dan utas latar belakang, maka berhati-hatilah untuk memastikan perilaku yang benar pada waktu proses. Kompilator Microsoft C++ mengeluarkan peringatan saat Anda membuat instans kelas run-time non-agile di aplikasi Anda pada cakupan global atau menyatakan jenis non-tangkas sebagai anggota kelas di kelas ref yang ditandai sebagai gesit.

Dari kelas non-tangkas, yang paling mudah ditangani adalah kelas yang memiliki ThreadingModel=Keduanya dan MarshallingType=Standar. Anda dapat membuat kelas-kelas ini gesar hanya dengan menggunakan kelas pembantu Agile<T> . Contoh berikut menunjukkan deklarasi objek jenis Windows::Security::Credentials::UI::CredentialPickerOptions^non-agile , dan peringatan kompilator yang dikeluarkan sebagai hasilnya.

ref class MyOptions
    {
    public:
        property Windows::Security::Credentials::UI::CredentialPickerOptions^ Options

        {
            Windows::Security::Credentials::UI::CredentialPickerOptions^ get()
            {
                return _myOptions;
            }
        }
    private:
        Windows::Security::Credentials::UI::CredentialPickerOptions^ _myOptions;
    };

Berikut adalah peringatan yang dikeluarkan:

Warning 1 warning C4451: 'Platform::Agile<T>::_object' : Usage of ref class 'Windows::Security::Credentials::UI::CredentialPickerOptions' inside this context can lead to invalid marshaling of object across contexts. Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead

Saat Anda menambahkan referensi—pada cakupan anggota atau cakupan global—ke objek yang memiliki perilaku marshaling "Standar", kompilator mengeluarkan peringatan yang menyarankan Anda untuk membungkus jenis di Platform::Agile<T>: Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead Jika Anda menggunakan Agile<T>, Anda dapat menggunakan kelas seperti Anda dapat kelas tangkas lainnya. Gunakan Platform::Agile<T> dalam keadaan ini:

  • Variabel non-agile dideklarasikan pada cakupan global.

  • Variabel non-agile dideklarasikan pada cakupan kelas dan ada kemungkinan bahwa mengonsumsi kode mungkin menyelundupkan pointer —yaitu, menggunakannya di apartemen yang berbeda tanpa marshaling yang benar.

Jika tidak satu pun dari kondisi tersebut berlaku, maka Anda dapat menandai kelas yang berisi sebagai non-agile. Dengan kata lain, Anda harus langsung menyimpan objek non-tangkas hanya di kelas non-agile, dan menyimpan objek non-tangkas melalui Platform::Agile<T> di kelas agile.

Contoh berikut menunjukkan cara menggunakan Agile<T> sehingga Anda dapat mengabaikan peringatan dengan aman.

#include <agile.h>
ref class MyOptions
    {
    public:
        property Windows::Security::Credentials::UI::CredentialPickerOptions^ Options

        {
            Windows::Security::Credentials::UI::CredentialPickerOptions^ get()
            {
                return m_myOptions.Get();
            }
        }
    private:
        Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions^> m_myOptions;

    };

Perhatikan bahwa Agile tidak dapat diteruskan sebagai nilai atau parameter pengembalian di kelas ref. Metode mengembalikan Agile<T>::Get() handle-to-object (^) yang dapat Anda berikan di seluruh antarmuka biner aplikasi (ABI) dalam metode publik atau properti.

Saat Anda membuat referensi ke kelas Windows Runtime dalam proc yang memiliki perilaku marshaling "None", pengkompilasi mengeluarkan peringatan C4451 tetapi tidak menyarankan agar Anda mempertimbangkan untuk menggunakan Platform::Agile<T>. Pengkompilasi tidak dapat menawarkan bantuan apa pun di luar peringatan ini, jadi Anda bertanggung jawab untuk menggunakan kelas dengan benar dan memastikan bahwa kode Anda memanggil komponen STA hanya dari utas antarmuka pengguna, dan komponen MTA hanya dari utas latar belakang.

Menulis komponen Windows Runtime yang tangkas

Saat Anda menentukan kelas ref di C++/CX, kelas ini gesit secara default—yaitu, kelas tersebut memiliki ThreadingModel=Keduanya dan MarshallingType=Agile. Jika Anda menggunakan Pustaka Templat Windows Runtime C++, Anda dapat membuat kelas Anda gesit FreeThreadedMarshallerdengan berasal dari FtmBase, yang menggunakan . Jika Anda menulis kelas yang memiliki ThreadingModel=Keduanya atau ThreadingModel=MTA, pastikan kelas tersebut aman untuk utas.

Anda dapat memodifikasi model utas dan perilaku marshaling kelas ref. Namun, jika Anda membuat perubahan yang merender kelas non-agile, Anda harus memahami implikasi yang terkait dengan perubahan tersebut.

Contoh berikut menunjukkan cara menerapkan MarshalingBehavior atribut dan ThreadingModel ke kelas runtime di pustaka kelas Runtime Windows. Saat aplikasi menggunakan DLL dan menggunakan ref new kata kunci untuk mengaktifkan MySTAClass objek kelas, objek diaktifkan di apartemen berulir tunggal dan tidak mendukung marshaling.

using namespace Windows::Foundation::Metadata;
using namespace Platform;

[Threading(ThreadingModel::STA)]
[MarshalingBehavior(MarshalingType::None)]
public ref class MySTAClass
{
};

Kelas yang tidak disegel harus memiliki pengaturan atribut marshaling dan threading sehingga pengkompilasi dapat memverifikasi bahwa kelas turunan memiliki nilai yang sama untuk atribut ini. Jika kelas tidak memiliki pengaturan yang diatur secara eksplisit, pengkompilasi menghasilkan kesalahan dan gagal dikompilasi. Kelas apa pun yang berasal dari unsealedclass menghasilkan kesalahan kompilator dalam salah satu kasus ini:

  • Atribut ThreadingModel dan MarshallingBehavior tidak didefinisikan dalam kelas turunan.

  • Nilai ThreadingModel atribut dan MarshallingBehavior di kelas turunan tidak cocok dengan yang ada di kelas dasar.

Informasi threading dan marshaling yang diperlukan oleh komponen Windows Runtime pihak ketiga ditentukan dalam informasi pendaftaran manifes aplikasi untuk komponen. Kami menyarankan agar Anda membuat semua komponen Windows Runtime Anda tangkas. Ini memastikan bahwa kode klien dapat memanggil komponen Anda dari utas apa pun di aplikasi, dan meningkatkan performa panggilan tersebut karena mereka adalah panggilan langsung yang tidak memiliki marshaling. Jika Anda menulis kelas Anda dengan cara ini, maka kode klien tidak perlu digunakan Platform::Agile<T> untuk menggunakan kelas Anda.

Baca juga

ThreadingModel
MarshallingBehavior