Condividi tramite


Appartamenti a thread singolo

L'uso di appartamenti a thread singolo (processo del modello apartment) offre un paradigma basato su messaggi per gestire più oggetti in esecuzione simultaneamente. Consente di scrivere codice più efficiente consentendo l'esecuzione di un thread, mentre attende il completamento di un'operazione dispendiosa in termini di tempo, per consentire l'esecuzione di un altro thread.

Ogni thread in un processo inizializzato come processo del modello apartment, che recupera e invia messaggi finestra, è un thread apartment a thread singolo. Ogni thread vive all'interno del proprio appartamento. All'interno di un apartment, i puntatori di interfaccia possono essere passati senza effettuare il marshalling e pertanto tutti gli oggetti in un thread apartment a thread singolo comunicano direttamente.

Un raggruppamento logico di oggetti correlati eseguiti nello stesso thread e pertanto deve avere un'esecuzione sincrona, potrebbe trovarsi nello stesso thread apartment a thread singolo. Tuttavia, un oggetto modello apartment non può risiedere su più di un thread. Le chiamate agli oggetti in altri thread devono essere effettuate all'interno del contesto del thread proprietario, in modo che i thread COM distribuiti vengano eseguiti automaticamente quando si chiama su un proxy.

I modelli interprocessi e interthread sono simili. Quando è necessario passare un puntatore di interfaccia a un oggetto in un altro apartment (su un altro thread) all'interno dello stesso processo, si usa lo stesso modello di marshalling usato dagli oggetti in processi diversi per passare puntatori attraverso i limiti del processo. Ottenendo un puntatore all'oggetto di marshalling standard, è possibile effettuare il marshalling dei puntatori di interfaccia attraverso i limiti del thread (tra appartamenti) nello stesso modo in cui si esegue tra i processi. I puntatori di interfaccia devono essere sottoposto a marshalling quando vengono passati tra appartamenti.

Le regole per gli appartamenti a thread singolo sono semplici, ma è importante seguirle attentamente:

  • Ogni oggetto deve essere attivo su un solo thread (all'interno di un apartment a thread singolo).
  • Inizializzare la libreria COM per ogni thread.
  • Effettuare il marshalling di tutti i puntatori agli oggetti quando li passano tra appartamenti.
  • Ogni apartment a thread singolo deve avere un ciclo di messaggi per gestire le chiamate da altri processi e appartamenti all'interno dello stesso processo. Anche gli appartamenti a thread singolo senza oggetti (solo client) necessitano di un ciclo di messaggi per inviare i messaggi di trasmissione usati da alcune applicazioni.
  • Gli oggetti basati su DLL o in-process non chiamano le funzioni di inizializzazione COM; registrano invece il modello di threading con threadingModel denominato-value nella chiave InprocServer32 nel Registro di sistema. Gli oggetti con riconoscimento degli appartamenti devono anche scrivere con attenzione punti di ingresso DLL. Esistono considerazioni speciali che si applicano ai server in-processing. Per altre informazioni, vedere Problemi di threading in-Process Server.

Mentre più oggetti possono vivere su un singolo thread, nessun oggetto modello apartment può vivere su più di un thread.

Ogni thread di un processo client o di un server out-of-process deve chiamare CoInitialize oppure chiamare CoInitializeEx e specificare COINIT_APARTMENTTHREADED per il parametro dwCoInit. L'appartamento principale è il thread che chiama prima CoInitializeEx . Per informazioni sui server in-process, vedere Problemi di threading del server in-process.

Tutte le chiamate a un oggetto devono essere effettuate sul relativo thread (all'interno del relativo apartment). Non è consentito chiamare un oggetto direttamente da un altro thread; l'uso di oggetti in questo modo a thread libero potrebbe causare problemi per le applicazioni. L'implicazione di questa regola è che tutti i puntatori agli oggetti devono essere sottoposto a marshalling quando vengono passati tra appartamenti. COM fornisce le due funzioni seguenti a questo scopo:

Queste funzioni esegono chiamate alle funzioni CoMarshalInterface e CoUnmarshalInterface, che richiedono l'uso del flag MSHCTX_INPROC.

In generale, il marshalling viene eseguito automaticamente da COM. Ad esempio, quando si passa un puntatore di interfaccia come parametro in una chiamata al metodo su un proxy a un oggetto in un altro apartment o quando si chiama CoCreateInstance, COM esegue automaticamente il marshalling. Tuttavia, in alcuni casi speciali, in cui il writer dell'applicazione passa puntatori di interfaccia tra appartamenti senza usare i normali meccanismi COM, il writer deve gestire manualmente il marshalling.

Se un appartamento (Apartment 1) in un processo dispone di un puntatore di interfaccia e un altro appartamento (Apartment 2) richiede il suo utilizzo, Apartment 1 deve chiamare CoMarshalInterThreadInterfaceInStream per effettuare il marshalling dell'interfaccia. Il flusso creato da questa funzione è thread-safe e deve essere archiviato in una variabile accessibile da Apartment 2. Apartment 2 deve passare questo flusso a CoGetInterfaceAndReleaseStream per annullare ilmarshal dell'interfaccia e restituirà un puntatore a un proxy tramite il quale può accedere all'interfaccia. L'appartamento principale deve rimanere attivo fino a quando il client non ha completato tutto il lavoro COM (perché alcuni oggetti in-process vengono caricati nell'apartment principale, come descritto in Problemi di threading del server in-process). Dopo che un oggetto è stato passato tra thread in questo modo, è molto facile passare puntatori di interfaccia come parametri. In questo modo, COM distribuito esegue il marshalling e il cambio di thread per l'applicazione.

Per gestire le chiamate da altri processi e appartamenti all'interno dello stesso processo, ogni apartment a thread singolo deve avere un ciclo di messaggi. Ciò significa che la funzione di lavoro del thread deve avere un ciclo GetMessage/DispatchMessage. Se vengono usate altre primitive di sincronizzazione per comunicare tra thread, la funzione MsgWaitForMultipleObjects può essere usata per attendere i messaggi e per gli eventi di sincronizzazione dei thread. La documentazione per questa funzione presenta un esempio di questo tipo di ciclo combinato.

COM crea una finestra nascosta usando la classe Windows "OleMainThreadWndClass" in ogni apartment a thread singolo. Una chiamata a un oggetto viene ricevuta come messaggio di finestra in questa finestra nascosta. Quando l'apartment dell'oggetto recupera e invia il messaggio, la finestra nascosta lo riceverà. La routine della finestra chiamerà quindi il metodo di interfaccia corrispondente dell'oggetto .

Quando più client chiamano un oggetto, le chiamate vengono accodate nella coda dei messaggi e l'oggetto riceverà una chiamata ogni volta che l'apartment recupera e invia messaggi. Poiché le chiamate vengono sincronizzate da COM e le chiamate vengono sempre recapitate dal thread che appartiene all'apartment dell'oggetto, le implementazioni dell'interfaccia dell'oggetto non devono fornire la sincronizzazione. Gli appartamenti a thread singolo possono implementare IMessageFilter per consentire loro di annullare le chiamate o ricevere messaggi di finestra quando necessario.

L'oggetto può essere immesso nuovamente se una delle implementazioni del metodo di interfaccia recupera e invia messaggi o effettua una chiamata ORPC a un altro thread, causando il recapito di un'altra chiamata all'oggetto (dallo stesso apartment). OLE non impedisce la reentrancy sullo stesso thread, ma può contribuire a garantire la thread safety. È identico al modo in cui è possibile immettere nuovamente una routine finestra se recupera e invia messaggi durante l'elaborazione di un messaggio. Tuttavia, la chiamata a un server apartment out-of-process a thread singolo che chiama un altro server apartment a thread singolo consentirà di immettere nuovamente il primo server.

Accesso alle interfacce tra appartamenti

Scelta del modello di threading

Appartamenti multithreading

Problemi di threading del server in-process

Processi, thread e appartamenti

Comunicazione a thread singolo e multithreading