Processi, thread e appartamenti
Un processo è una raccolta di spazio di memoria virtuale, codice, dati e risorse di sistema. Un thread è codice che deve essere eseguito serialmente all'interno di un processo. Un processore esegue thread, non processi, quindi ogni applicazione ha almeno un processo e un processo ha sempre almeno un thread di esecuzione, noto come thread primario. Un processo può avere più thread oltre al thread primario.
I processi comunicano tra loro tramite messaggi, usando la tecnologia RPC (Remote Procedure Call) di Microsoft per passare le informazioni l'una all'altra. Non esiste alcuna differenza per il chiamante tra una chiamata proveniente da un processo in un computer remoto e una chiamata proveniente da un altro processo nello stesso computer.
Quando un thread inizia a essere eseguito, continua fino a quando non viene terminato o finché non viene interrotto da un thread con priorità più alta (da un'azione dell'utente o dall'utilità di pianificazione del thread del kernel). Ogni thread può eseguire sezioni separate di codice o più thread possono eseguire la stessa sezione di codice. I thread che eseguono lo stesso blocco di codice mantengono stack separati. Ogni thread in un processo condivide le variabili e le risorse globali del processo.
L'utilità di pianificazione del thread determina quando e con quale frequenza eseguire un thread, in base a una combinazione dell'attributo della classe di priorità del processo e della priorità di base del thread. Per impostare l'attributo della classe di priorità di un processo, chiamare la funzione SetPriorityClass e impostare la priorità di base di un thread con una chiamata a SetThreadPriority.
Le applicazioni multithreading devono evitare due problemi di threading: deadlock e race. Un deadlock si verifica quando ogni thread è in attesa dell'altra operazione. Il controllo chiamate COM consente di evitare deadlock nelle chiamate tra oggetti. Una race condition si verifica quando un thread termina prima di un altro da cui dipende, causando l'uso di un valore non inizializzato in precedenza perché quest'ultimo non ne ha ancora fornito uno valido. COM fornisce alcune funzioni appositamente progettate per evitare race condition nei server out-of-process. (Vedere Helper di implementazione del server out-of-process.
L'apartment e l'architettura del threading COM
Mentre COM supporta il modello a thread singolo per processo prevalente prima dell'introduzione di più thread di esecuzione, è possibile scrivere codice per sfruttare i vantaggi di più thread, ottenendo applicazioni più efficienti, consentendo l'esecuzione di un thread mentre un altro thread attende il completamento di un'operazione dispendiosa in termini di tempo.
Nota
L'uso di più thread non garantisce prestazioni migliori. Infatti, poiché il factoring del thread è un problema difficile, l'uso di più thread spesso causa problemi di prestazioni. La chiave consiste nell'usare più thread solo se si è certi di ciò che si sta facendo.
In generale, il modo più semplice per visualizzare l'architettura di threading COM è pensare a tutti gli oggetti COM nel processo come divisi in gruppi chiamati appartamenti. Un oggetto COM vive esattamente in un appartamento, nel senso che i suoi metodi possono essere chiamati direttamente solo da un thread che appartiene a quell'appartamento. Qualsiasi altro thread che vuole chiamare l'oggetto deve passare attraverso un proxy.
Ci sono due tipi di appartamenti: appartamenti a thread singolo, e appartamenti multithreading.
- Gli appartamenti a thread singolo sono costituiti da un solo thread, quindi tutti gli oggetti COM che risiedono in un apartment a thread singolo possono ricevere chiamate di metodo solo dal thread che appartiene a tale apartment. Tutte le chiamate di metodo a un oggetto COM in un apartment a thread singolo vengono sincronizzate con la coda di messaggi di Windows per il thread dell'apartment a thread singolo. Un processo con un singolo thread di esecuzione è semplicemente un caso speciale di questo modello.
- Gli appartamenti multithreading sono costituiti da uno o più thread, quindi tutti gli oggetti COM che risiedono in un apartment multithreading possono ricevere chiamate di metodo direttamente da qualsiasi thread appartenente all'apartment multithreading. I thread in un apartment multithreading usano un modello denominato threading libero. Le chiamate agli oggetti COM in un apartment multithreading vengono sincronizzate dagli oggetti stessi.
Nota
Per una descrizione della comunicazione tra appartamenti a thread singolo e appartamenti multithreading all'interno dello stesso processo, vedere Comunicazione a thread singolo e multithreading.
Un processo può avere zero o più appartamenti a thread singolo e zero o un appartamento multithreading.
In un processo, l'appartamento principale è il primo a essere inizializzato. In un processo a thread singolo, questo è l'unico appartamento. I parametri di chiamata vengono sottoposti a marshalling tra appartamenti e COM gestisce la sincronizzazione tramite messaggistica. Se si designano più thread in un processo per essere a thread libero, tutti i thread liberi risiedono in un singolo apartment, i parametri vengono passati direttamente a qualsiasi thread nell'apartment ed è necessario gestire tutta la sincronizzazione. In un processo con threading libero e threading apartment, tutti i thread liberi risiedono in un unico appartamento e tutti gli altri appartamenti sono appartamenti a thread singolo. Un processo che esegue il lavoro COM è una raccolta di appartamenti con, al massimo, un appartamento multithreading, ma qualsiasi numero di appartamenti a thread singolo.
I modelli di threading in COM forniscono il meccanismo per client e server che usano architetture di threading diverse per collaborare. Le chiamate tra oggetti con modelli di threading diversi in processi diversi sono naturalmente supportate. Dal punto di vista dell'oggetto chiamante, tutte le chiamate agli oggetti all'esterno di un processo si comportano in modo identico, indipendentemente dalla modalità di threading dell'oggetto chiamato. Analogamente, dal punto di vista dell'oggetto chiamato, le chiamate in arrivo si comportano in modo identico, indipendentemente dal modello di threading del chiamante.
L'interazione tra un client e un oggetto out-of-process è semplice, anche quando usano modelli di threading diversi perché il client e l'oggetto si trovano in processi diversi. COM, interposed tra il client e il server, può fornire il codice per i modelli di threading da interagire, usando il marshalling standard e RPC. Ad esempio, se un oggetto a thread singolo viene chiamato simultaneamente da più client a thread libero, le chiamate verranno sincronizzate da COM inserendo i messaggi di finestra corrispondenti nella coda dei messaggi del server. L'appartamento dell'oggetto riceverà una chiamata ogni volta che recupera e invia messaggi. Tuttavia, è necessario prestare attenzione per garantire che i server in-process interagiscono correttamente con i client. (Vedere Problemi di threading del server in-process.
Il problema più importante nella programmazione con un modello multithreading consiste nel rendere thread-safe il codice in modo che i messaggi destinati a un determinato thread vadano solo a quel thread e l'accesso ai thread sia protetto.
Per ulteriori informazioni, vedi gli argomenti seguenti:
- Scelta del modello di threading
- Appartamenti a thread singolo
- Appartamenti multithreading
- Comunicazione a thread singolo e multithreading
- Problemi di threading del server in-process
- Accesso alle interfacce tra appartamenti