Potresti spiegare STA e MTA?


Risposte:


361

Il modello di threading COM viene chiamato modello "apartment", in cui il contesto di esecuzione degli oggetti COM inizializzati è associato a un singolo thread (Single Thread Apartment) o molti thread (Multi Thread Apartment). In questo modello, un oggetto COM, una volta inizializzato in un appartamento, fa parte di tale appartamento per la durata del suo runtime.

Il modello STA viene utilizzato per oggetti COM che non sono thread-safe. Ciò significa che non gestiscono la propria sincronizzazione. Un uso comune di questo è un componente dell'interfaccia utente. Pertanto, se un altro thread deve interagire con l'oggetto (come premere un pulsante in un modulo), il messaggio viene inviato al thread STA. Il sistema di pompaggio dei messaggi di Windows Form ne è un esempio.

Se l'oggetto COM è in grado di gestire la propria sincronizzazione, è possibile utilizzare il modello MTA in cui più thread possono interagire con l'oggetto senza chiamate con marshalling.


1
Una buona lettura per ulteriori dettagli: INFO: descrizioni e lavorazioni dei modelli di filettatura OLE .
noseratio,

208

Dipende tutto da come vengono gestite le chiamate agli oggetti e da quanta protezione hanno bisogno. Gli oggetti COM possono chiedere al runtime di proteggerli dall'essere richiamati da più thread contemporaneamente; quelli che non possono potenzialmente essere chiamati contemporaneamente da thread diversi, quindi devono proteggere i propri dati.

Inoltre, è anche necessario che il runtime impedisca a una chiamata di oggetto COM di bloccare l'interfaccia utente, se viene effettuata una chiamata da un thread dell'interfaccia utente.

Un appartamento è un luogo in cui gli oggetti possono vivere e contengono uno o più thread. L'appartamento definisce cosa succede quando vengono effettuate le chiamate. Le chiamate agli oggetti in un appartamento saranno ricevute ed elaborate su qualsiasi thread in quell'appartamento, con l'eccezione che una chiamata da un thread già nell'appartamento giusto viene elaborata da sola (cioè una chiamata diretta all'oggetto).

I thread possono essere in un appartamento a thread singolo (nel qual caso sono l'unico thread in quell'appartamento) o in un appartamento a thread multipli. Specificare quale quando il thread inizializza COM per quel thread.

STA è principalmente per la compatibilità con l'interfaccia utente, che è legata a un thread specifico. Un STA riceve le notifiche delle chiamate da elaborare ricevendo un messaggio da una finestra nascosta; quando effettua una chiamata in uscita, avvia un ciclo di messaggi modale per impedire l'elaborazione di altri messaggi della finestra. È possibile specificare un filtro messaggi da chiamare, in modo che l'applicazione possa rispondere ad altri messaggi.

Al contrario, tutti i thread MTA condividono un singolo MTA per il processo. COM può avviare un nuovo thread di lavoro per gestire una chiamata in arrivo se non sono disponibili thread, fino a un limite di pool. I thread che effettuano chiamate in uscita semplicemente bloccano.

Per semplicità considereremo solo gli oggetti implementati nelle DLL, che pubblicizzano nel registro ciò che supportano, impostando il ThreadingModelvalore per la chiave della loro classe. Esistono quattro opzioni:

  • Discussione principale ( ThreadingModelvalore non presente). L'oggetto viene creato sul thread dell'interfaccia utente principale dell'host e tutte le chiamate vengono indirizzate a quel thread. Il factory di classe verrà chiamato solo su quel thread.
  • Apartment. Ciò indica che la classe può essere eseguita su qualsiasi thread in modalità a thread singolo. Se il thread che lo crea è un thread STA, l'oggetto verrà eseguito su quel thread, altrimenti verrà creato nello STA principale - se non esiste STA principale, verrà creato un thread STA per esso. (Ciò significa che i thread MTA che creano oggetti Apartment eseguiranno il marshalling di tutte le chiamate a un thread diverso.) Il factory di classe può essere chiamato contemporaneamente da più thread STA, quindi deve proteggere i suoi dati interni da questo.
  • Free. Ciò indica una classe progettata per l'esecuzione nell'MTA. Verrà sempre caricato nell'MTA, anche se creato da un thread STA, il che significa di nuovo che le chiamate del thread STA verranno raggruppate. Questo perché un Freeoggetto è generalmente scritto con l'aspettativa che possa bloccarsi.
  • Both. Queste classi sono flessibili e si caricano in qualsiasi appartamento da cui sono state create. Devono essere scritti per soddisfare entrambi i set di requisiti, tuttavia: devono proteggere il loro stato interno da chiamate simultanee, nel caso in cui siano caricati nell'MTA, ma non devono bloccare, nel caso in cui siano caricati in uno STA.

Da .NET Framework, in pratica basta usare [STAThread]su qualsiasi thread che crea l'interfaccia utente. I thread di lavoro devono utilizzare l'MTA, a meno che non utilizzino Apartmentcomponenti COM con contrassegno, nel qual caso utilizzare STA per evitare problemi di sovraccarico e scalabilità di marshalling se lo stesso componente viene chiamato da più thread (poiché ogni thread dovrà attendere il componente a sua volta). È molto più semplice se si utilizza un oggetto COM separato per thread, indipendentemente dal fatto che il componente sia in STA o MTA.


Mi piace la tua ultima conclusione, ma riguardo a ciò, cosa dovrei fare se voglio che nella mia UI aggiunga un UserControl che l'unica cosa che fa è riprodurre un gif (come un caricatore) ... Sto avendo problemi con questo , la gif non gira se sono nello stesso thread ... e non sono sicuro che MTA sull'interfaccia utente sia un'ottima idea, cosa faresti?
Yogurtu,

2
@Yogurtu: Perché sei preoccupato del modello di threading COM? La decisione STA / MTA è rilevante solo se si utilizzano oggetti COM nel codice. Non è possibile utilizzare MTA per l'interfaccia utente: gli interni di .NET non devono essere utilizzati in questo modo. Se l'animazione si interrompe, è perché hai smesso di pompare i messaggi sul tuo thread dell'interfaccia utente. Spostare le operazioni di lunga durata in un BackgroundWorker o dividerle in piccoli passaggi. Il lavoro richiede <16ms per mantenere un'animazione fluida a 60Hz!
Mike Dimmick,

Qual è la differenza tra "appartamento" e appdomain?
Puchacz,

78

Trovo che le spiegazioni esistenti siano troppo inghiottite. Ecco la mia spiegazione in inglese semplice:

STA: se un thread crea un oggetto COM impostato su STA (quando si chiama CoCreateXXX è possibile passare un flag che imposta l'oggetto COM sulla modalità STA), solo questo thread può accedere a questo oggetto COM (questo è ciò che significa STA - Single Threaded Apartment ), un altro thread che tenta di chiamare metodi su questo oggetto COM viene trasformato silenziosamente nel recapito dei messaggi al thread che crea (possiede) l'oggetto COM. Questo è molto simile al fatto che solo il thread che ha creato un controllo UI può accedervi direttamente. E questo meccanismo ha lo scopo di prevenire complicate operazioni di blocco / sblocco.

MTA: se un thread crea un oggetto COM impostato su MTA, praticamente ogni thread può chiamare direttamente i metodi su di esso.

Questo è praticamente l'essenza. Sebbene tecnicamente ci siano alcuni dettagli che non ho menzionato, come nel paragrafo "STA", il thread del creatore deve essere esso stesso STA. Ma questo è praticamente tutto ciò che devi sapere per capire STA / MTA / NA.


23

STA (Single Threaded Apartment) è fondamentalmente il concetto che solo un thread interagirà con il tuo codice alla volta. Le chiamate nel tuo appartamento vengono trasferite tramite messaggi di Windows (usando una finestra non visibile). Ciò consente di mettere in coda le chiamate e attendere il completamento delle operazioni.

MTA (Multi Threaded Apartment) è il luogo in cui molti thread possono funzionare tutti contemporaneamente e l'onere è tuo sviluppatore per gestire la sicurezza dei thread.

C'è molto di più da imparare sul threading dei modelli in COM, ma se hai problemi a capire cosa sono, direi che capire cosa sia lo STA e come funziona sarebbe il miglior punto di partenza perché la maggior parte degli oggetti COM sono STA.

Thread appartamento, se un thread vive nello stesso appartamento dell'oggetto che sta usando, allora è un thread appartamento. Penso che questo sia solo un concetto COM perché è solo un modo di parlare degli oggetti e dei fili con cui interagiscono ...


19

Ogni EXE che ospita i controlli COM o OLE definisce lo stato dell'appartamento. Lo stato dell'appartamento è STA predefinito (e per la maggior parte dei programmi dovrebbe essere STA).

STA - Tutti i controlli OLE per necessità devono vivere in uno STA. STA significa che l'oggetto COM deve essere sempre manipolato sul thread dell'interfaccia utente e non può essere passato ad altri thread (proprio come qualsiasi elemento dell'interfaccia utente in MFC). Tuttavia, il tuo programma può avere ancora molti thread.

MTA : è possibile manipolare l'oggetto COM su qualsiasi thread nel programma.


13
"STA significa che il tuo oggetto COM deve essere sempre manipolato sul thread dell'interfaccia utente" Non credo che sia esattamente giusto ... non deve essere sul thread "UI", solo un thread STA che ha un message pump su di esso perché chiama sincronizzato usando i messaggi. Il thread dell'interfaccia utente in genere soddisfa questi requisiti, ma non è l'unica possibilità.
Brian ONeil,

12

A mio avviso, l'appartamento viene utilizzato per proteggere gli oggetti COM da problemi multi-threading.

Se un oggetto COM non è thread-safe, dovrebbe dichiararlo come oggetto STA. Quindi solo il thread che lo crea può accedervi. Il thread di creazione dovrebbe dichiararsi come thread STA. Sotto il cofano, il thread memorizza le informazioni STA nel suo TLS (Thread Local Storage). Chiamiamo questo comportamento in quanto il thread entra in un appartamento STA. Quando altri thread vogliono accedere a questo oggetto COM, dovrebbe eseguire il marshalling dell'accesso al thread di creazione. Fondamentalmente, il thread di creazione utilizza il meccanismo dei messaggi per elaborare le chiamate inbound.

Se un oggetto COM è thread-safe, dovrebbe dichiararlo come oggetto MTA. L'oggetto MTA è accessibile da multi-thread.


4

Il codice che chiama le DLL degli oggetti COM (ad esempio, per leggere i file di dati proprietari), potrebbe funzionare bene in un'interfaccia utente ma appendere misteriosamente a un servizio. Il motivo è che a partire dalle interfacce utente .Net 2.0 assumono STA (thread-safe) mentre i servizi assumono MTA ((prima, i servizi assumevano STA). La necessità di creare un thread STA per ogni chiamata COM in un servizio può aggiungere un notevole sovraccarico.

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.