Helper di implementazione del server out-of-process
Sono disponibili quattro funzioni helper che possono essere chiamate dai server out-of-process per semplificare il processo di scrittura del codice del server. I client COM e i server COM in-process in genere non li chiamano. Queste funzioni sono progettate per impedire le race condition nell'attivazione del server quando i server hanno più appartamenti o più oggetti classe. Tuttavia, possono anche essere usati facilmente per server a thread singolo e a oggetti a classe singola. Le funzioni sono le seguenti:
Per arrestare correttamente, un server COM deve tenere traccia del numero di istanze di oggetto di cui è stata creata un'istanza e del numero di chiamate del metodo IClassFactory::LockServer . Solo quando entrambi questi conteggi raggiungono zero possono arrestare un server. Nei server COM a thread singolo, la decisione di arrestare è stata coordinata con le richieste di attivazione in ingresso, che sono state serializzate dalla coda dei messaggi. Il server, dopo aver ricevuto una versione nell'istanza finale dell'oggetto e decidendo di arrestare, revocava i relativi oggetti classe prima dell'invio di altre richieste di attivazione. Se una richiesta di attivazione è arrivata dopo questo punto, COM riconoscerebbe che gli oggetti di classe sono stati revocati e restituivano un errore a Service Control Manager (SCM), causando l'esecuzione di una nuova istanza del processo del server locale.
Tuttavia, in un server modello apartment, in cui oggetti di classe diversi vengono registrati in appartamenti diversi e in tutti i server a thread libero, questa decisione di arrestare deve essere coordinata con le richieste di attivazione su più thread in modo che un thread del server non decida di arrestarsi mentre un altro thread del server è occupato a distribuire oggetti classe o istanze di oggetti. Un approccio classico ma complesso per risolvere questo problema consiste nell'avere il server, dopo aver revocato i relativi oggetti di classe, controllare nuovamente il numero di istanze e rimanere attivo fino a quando non vengono rilasciate tutte le istanze.
Per semplificare la gestione di questi tipi di race condition, COM offre due funzioni di conteggio dei riferimenti:
- CoAddRefServerProcess incrementa un conteggio globale dei riferimenti per processo.
- CoReleaseServerProcess decrementa il conteggio dei riferimenti globali per processo.
Quando il conteggio dei riferimenti globali per processo raggiunge zero, COM chiama automaticamente CoSuspendClassObjects, che impedisce l'arrivo di nuove richieste di attivazione. Il server può quindi annullare la registrazione dei vari oggetti di classe dai vari thread a tempo libero senza preoccuparsi che venga inserita un'altra richiesta di attivazione. Tutte le nuove richieste di attivazione vengono quindi gestite da SCM avviando una nuova istanza del processo del server locale.
Il modo più semplice per usare queste funzioni da parte di un'applicazione server locale consiste nel chiamare CoAddRefServerProcess nel costruttore per ogni oggetto istanza e in ognuno dei relativi metodi IClassFactory::LockServer quando il parametro fLock è TRUE. L'applicazione server deve anche chiamare CoReleaseServerProcess nel distruttore di ognuno dei relativi oggetti di istanza e in ognuno dei relativi metodi IClassFactory::LockServer quando il parametro fLock è FAL edizione Standard.
Infine, l'applicazione server deve prestare attenzione al codice restituito da CoReleaseServerProcess e, se restituisce 0, l'applicazione server deve avviare la pulizia, che, per un server con più thread, in genere significa che deve segnalare i vari thread per uscire dai cicli di messaggi e chiamare CoAddRefServerProcess e CoReleaseServerProcess. Se vengono usate le funzioni di gestione della durata dei processi del server, devono essere usate sia nelle istanze dell'oggetto che nel metodo LockServer . In caso contrario, l'applicazione server potrebbe essere arrestata in modo anomalo.
Quando viene effettuata una richiesta CoGetClassObject, COM contatta il server, effettua il marshalling dell'interfaccia IClassFactory dell'oggetto classe, torna al processo client, annulla ilmarshal dell'interfaccia IClassFactory e lo restituisce al client. A questo punto, i client chiamano in genere LockServer con TRUE per impedire l'arresto del processo del server. Tuttavia, esiste un intervallo di tempo tra il marshalling dell'oggetto classe e quando il client chiama LockServer in cui un altro client potrebbe connettersi allo stesso server, ottenere un'istanza e rilasciare tale istanza, causando l'arresto del server e lasciando il primo client elevato e asciutto con un puntatore IClassFactory disconnesso. Per evitare questa race condition, COM aggiunge una chiamata implicita a LockServer con TRUE all'oggetto classe quando esegue il marshalling dell'interfaccia IClassFactory e una chiamata implicita a LockServer con FAL edizione Standard quando il client rilascia l'interfaccia IClassFactory. Pertanto, non è necessario eseguire chiamate Remote LockServer al server e il proxy per LockServer restituisce semplicemente S_OK senza effettivamente comunicazione remota della chiamata.
Durante l'inizializzazione di un processo server out-of-process è presente un'altra race condition correlata all'attivazione. Un server COM che registra più classi chiama in genere CoRegisterClassObject con REGCLS_LOCAL_edizione Standard RVER per ogni CLSID supportato. Dopo aver eseguito questa operazione per tutte le classi, il server immette il ciclo di messaggi. Per un server COM a thread singolo, tutte le richieste di attivazione vengono bloccate fino a quando il server non entra nel ciclo di messaggi. Tuttavia, per un server modello apartment che registra oggetti di classe diversi in appartamenti diversi e per tutti i server a thread libero, le richieste di attivazione possono arrivare prima di questo. Nel caso dei server modello apartment, le richieste di attivazione potrebbero arrivare non appena un thread ha immesso il ciclo di messaggi. Nel caso di server a thread libero, una richiesta di attivazione potrebbe arrivare non appena viene registrato il primo oggetto classe. Poiché un'attivazione può verificarsi in anticipo, è anche possibile che la versione finale si verifichi (e quindi causare l'arresto del server) prima che il resto del server abbia avuto la possibilità di completare l'inizializzazione.
Per eliminare queste race condition e semplificare il processo del writer del server, qualsiasi server che desidera registrare più oggetti di classe con COM deve chiamare CoRegisterClassObject con REGCLS_LOCAL_edizione Standard RVER | REGCLS_SUSPENDED per ogni CLSID diverso supportato dal server. Dopo che tutte le classi sono state registrate e il processo del server è pronto per accettare le richieste di attivazione in ingresso, il server deve effettuare una chiamata a CoResumeClassObjects. Questa funzione indica a COM di informare SCM su tutte le classi registrate e inizia a consentire le richieste di attivazione nel processo server. L'uso di queste funzioni offre i vantaggi seguenti:
- Viene effettuata una sola chiamata a SCM, indipendentemente dal numero di CLSID registrati, riducendo così il tempo di registrazione complessivo (e quindi l'ora di avvio dell'applicazione server).
- Se il server dispone di più appartamenti e CLSID diversi vengono registrati in appartamenti diversi o se il server è un server a thread libero, non verranno richieste di attivazione finché il server non chiama CoResumeClassObjects, dando al server la possibilità di registrare tutti i CLSID e di essere configurati correttamente prima di dover gestire le richieste di attivazione e le possibili richieste di arresto.
Argomenti correlati