ApartmentState for dummies


120

Ho appena corretto un bug usando questo:

_Thread.SetApartmentState(ApartmentState.STA);

Ora vorrei capire cosa significa e perché funziona!


1
Questo post può aiutarti
Arsen Mkrtchyan

Risposte:


236

COM è il nonno di .NET. Avevano obiettivi piuttosto elevati con esso, una delle cose che fa COM ma .NET salta completamente è fornire garanzie di threading per una classe. Una classe COM può pubblicare il tipo di requisiti di threading di cui dispone. E l'infrastruttura COM garantisce che tali requisiti siano soddisfatti.

Questo è completamente assente in .NET. Puoi usare un oggetto Queue <> ad esempio in più thread, ma se non ti blocchi correttamente, avrai un brutto bug nel tuo codice che è molto difficile da diagnosticare.

I dettagli esatti del threading COM sono troppo grandi per essere contenuti in un post. Mi concentrerò sui dettagli della tua domanda. Un thread che crea oggetti COM deve indicare a COM quale tipo di supporto desidera fornire alle classi COM che hanno opzioni di threading limitate. La stragrande maggioranza di queste classi supporta solo il cosiddetto threading Apartment, i loro metodi di interfaccia possono essere chiamati in sicurezza solo dallo stesso thread che ha creato l'istanza. In altre parole, annunciano "Non supporto in alcun modo il threading, per favore fate attenzione a non chiamarmi mai dal thread sbagliato". Anche se il codice client lo chiama effettivamente da un altro thread.

Esistono due tipi, STA (Single Threaded Apartment) e MTA. È specificato nella chiamata CoInitializeEx (), una funzione che deve essere chiamata da qualsiasi thread che esegue qualsiasi operazione con COM. Il CLR effettua quella chiamata automaticamente ogni volta che avvia un thread. Per il thread di avvio principale del programma, ottiene il valore da passare dall'attributo [STAThread] o [MTAThread] sul metodo Main (). L'impostazione predefinita è MTA. Per i thread che crei tu stesso, è determinato dalla tua chiamata a SetApartmentState (). L'impostazione predefinita è MTA. I thread del pool di thread sono sempre MTA, che non possono essere modificati.

C'è molto codice in Windows che richiede un STA. Esempi notevoli che useresti tu stesso sono gli Appunti, Drag + Drop e le finestre di dialogo della shell (come OpenFileDialog). E un sacco di codice che non puoi vedere, come i programmi di automazione dell'interfaccia utente e gli hook per osservare i messaggi. Nessuno di quel codice deve essere thread-safe, il suo autore avrebbe difficoltà a renderlo sicuro senza sapere in quale programma viene utilizzato. Di conseguenza, il thread dell'interfaccia utente di un progetto WPF o Windows Form deve sempre essere STA per supportare tale codice, così come qualsiasi thread che crea una finestra.

La promessa si fanno a COM che il thread sta STA tuttavia non si richiede di seguire il contratto appartamento single-thread. Sono piuttosto rigidi e puoi diventare difficile diagnosticare problemi quando rompi il contratto. I requisiti sono che non si blocchi mai il thread per un certo periodo di tempo e che si pompi un loop di messaggi. Quest'ultimo requisito è soddisfatto da un thread dell'interfaccia utente di WPF o Winforms, ma dovrai occupartene tu stesso se crei il tuo thread STA. La diagnostica comune per la rottura del contratto è il deadlock.

C'è un bel po 'di supporto integrato nel CLR per supportare questi requisiti tra l'altro, aiutandoti a tenerti fuori dai guai. Il istruzione lock ei metodi WaitOne () pompano un loop di messaggi quando si blocca su un thread STA. Questo tuttavia si occupa solo del requisito del blocco maiuscolo, è comunque necessario creare il proprio loop di messaggi. Application.Run () sia in WPF che in Winforms.

In precedenza ho fornito una risposta che contiene maggiori dettagli sull'importanza di avere un loop di messaggi per mantenere felice COM. Troverai il post qui .


4
Ottima risposta! Il bug che ho risolto era per un thread che ho creato per un generatore di report di lunga durata che utilizzava i controlli WPF per creare parti del report, quindi ha senso, anche se non sono a conoscenza del fatto che quel thread abbia un loop di messaggi su di esso .
Benjol

4
Ho dovuto leggere seriamente più volte il post MSDN per capirlo, la tua risposta è molto chiara e ben scritta. Grazie!
ak3nat0n
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.