ApartmentState untuk boneka

120

Saya baru saja memperbaiki bug menggunakan ini:

_Thread.SetApartmentState(ApartmentState.STA);

Sekarang saya ingin memahami apa artinya, dan mengapa ini berhasil!

Benjol
sumber
1
Posting ini dapat membantu Anda
Arsen Mkrtchyan

Jawaban:

236

COM adalah kakek dari .NET. Mereka memiliki tujuan yang cukup tinggi dengannya, salah satu hal yang dilakukan COM tetapi .NET sepenuhnya dilewati adalah memberikan jaminan threading untuk sebuah kelas. Kelas COM dapat mempublikasikan jenis persyaratan penguliran yang dimilikinya. Dan infrastruktur COM memastikan persyaratan tersebut terpenuhi.

Ini sama sekali tidak ada di .NET. Anda dapat menggunakan objek Queue <> misalnya di beberapa utas, tetapi jika Anda tidak mengunci dengan benar, Anda akan memiliki bug parah dalam kode Anda yang sangat sulit untuk didiagnosis.

Detail pasti dari penguliran COM terlalu besar untuk dimuat dalam sebuah kiriman. Saya akan fokus pada pertanyaan spesifik Anda. Sebuah utas yang membuat objek COM harus memberi tahu COM jenis dukungan apa yang ingin diberikannya kepada kelas COM yang memiliki opsi threading terbatas. Sebagian besar class tersebut hanya mendukung apa yang disebut Apartment threading, metode antarmukanya hanya dapat dipanggil dengan aman dari thread yang sama yang membuat instance. Dengan kata lain, mereka mengumumkan "Saya tidak mendukung threading apa pun, harap berhati-hati agar jangan pernah menelepon saya dari utas yang salah". Bahkan jika kode klien benar - benar memanggilnya dari utas lain.

Ada dua macam, STA (Single Threaded Apartment) dan MTA. Ini ditentukan dalam panggilan CoInitializeEx (), fungsi yang harus dipanggil oleh utas apa pun yang melakukan apa pun dengan COM. CLR membuat panggilan itu secara otomatis setiap kali ia memulai utas. Untuk utas startup utama program Anda, ia mendapatkan nilai untuk diteruskan dari atribut [STAThread] atau [MTAThread] pada metode Main () Anda. Default-nya adalah MTA. Untuk utas yang Anda buat sendiri, ini ditentukan oleh panggilan Anda ke SetApartmentState (). Default-nya adalah MTA. Utas threadpool selalu MTA, yang tidak dapat diubah.

Ada banyak kode di Windows yang membutuhkan STA. Contoh penting yang Anda gunakan sendiri adalah Clipboard, Drag + Drop dan dialog shell (seperti OpenFileDialog). Dan banyak kode yang tidak dapat Anda lihat, seperti program Otomasi UI dan kait untuk mengamati pesan. Tak satu pun dari kode itu harus aman untuk thread, pembuatnya akan mengalami kesulitan untuk membuatnya aman tanpa mengetahui di program mana ia akan digunakan. Karenanya, utas UI dari proyek WPF atau Windows Forms harus selalu STA untuk mendukung kode tersebut, seperti halnya utas apa pun yang membuat jendela.

Janji yang Anda buat untuk COM bahwa benang Anda STA namun tidak mengharuskan Anda untuk mengikuti kontrak apartemen single-thread. Mereka cukup kaku dan Anda bisa jadi sulit untuk mendiagnosis masalah saat Anda melanggar kontrak. Persyaratannya adalah Anda tidak pernah memblokir thread selama berapa pun dan Anda memompa loop pesan. Persyaratan terakhir dipenuhi oleh utas UI WPF atau Winforms tetapi Anda harus mengurusnya sendiri jika Anda membuat utas STA Anda sendiri. Diagnosis umum untuk melanggar kontrak adalah kebuntuan.

Ada cukup banyak dukungan built-in CLR untuk mendukung persyaratan ini, membantu Anda menghindari masalah. The kunci pernyataan dan WaitOne () metode pompa pesan loop ketika blok di thread STA. Namun ini hanya menangani persyaratan tidak pernah-blokir, Anda masih perlu membuat loop pesan Anda sendiri. Application.Run () di WPF dan Winforms.

Saya sebelumnya telah menyumbangkan jawaban yang berisi lebih banyak detail tentang pentingnya memiliki loop pesan untuk membuat COM senang. Anda akan menemukan postingannya di sini .

Hans Passant
sumber
4
Jawaban yang sangat bagus! Bug yang saya selesaikan adalah untuk utas yang saya buat untuk pembuat laporan yang berjalan lama yang menggunakan kontrol WPF untuk membuat bagian-bagian laporan, jadi itu masuk akal, meskipun saya tidak tahu bahwa utas itu memiliki loop pesan di atasnya .
Benjol
4
Saya benar-benar harus membaca posting MSDN beberapa kali untuk memahaminya, Jawaban Anda sangat jelas dan ditulis dengan baik. Terima kasih!
ak3nat0n