Problemi di threading del server in-process
Un server in-process non chiama CoInitialize, CoInitializeEx o OleInitialize per contrassegnare il modello di threading. Per gli oggetti basati su DLL o in-process basati su thread, è necessario impostare il modello di threading nel Registro di sistema. Il modello predefinito quando non si specifica un modello di threading è a thread singolo per processo. Per specificare un modello, aggiungere il valore ThreadingModel alla chiave InprocServer32 nel Registro di sistema.
Le DLL che supportano la creazione di istanze di un oggetto classe devono implementare ed esportare le funzioni DllGetClassObject e DllCanUnloadNow. Quando un client desidera un'istanza della classe supportata dalla DLL, una chiamata a CoGetClassObject (direttamente o tramite una chiamata a CoCreateInstance) chiama DllGetClassObject per ottenere un puntatore al relativo oggetto classe quando l'oggetto viene implementato in una DLL. DllGetClassObject deve quindi essere in grado di fornire più oggetti di classe o un singolo oggetto thread-safe (essenzialmente usando InterlockedIncrement/InterlockedDecrement sui conteggi dei riferimenti interni).
Come suggerisce il nome, DllCanUnloadNow viene chiamato per determinare se la DLL che lo implementa è in uso, consentendo al chiamante di scaricarlo in modo sicuro se non lo è. Chiamate a CoFreeUnusedLibraries da qualsiasi thread instradano sempre attraverso il thread dell'apartment principale per chiamare DllCanUnloadNow.
Analogamente ad altri server, i server in-process possono essere a thread singolo, threading apartment o threading libero. Questi server possono essere usati da qualsiasi client OLE, indipendentemente dal modello di threading usato da tale client.
Tutte le combinazioni di interoperabilità del modello di threading sono consentite tra i client e gli oggetti in-process. L'interazione tra un client e un oggetto in-process che usano modelli di threading diversi è esattamente come l'interazione tra client e server out-of-process. Per un server in-process, quando il modello di threading del client e del server in-process differisce, COM deve interposersi tra il client e l'oggetto.
Quando un oggetto in-process che supporta il modello a thread singolo viene chiamato simultaneamente da più thread di un client, COM non può consentire ai thread client di accedere direttamente all'interfaccia dell'oggetto" l'oggetto non è stato progettato per tale accesso. Com deve invece assicurarsi che le chiamate siano sincronizzate e vengano effettuate solo dal thread client che ha creato l'oggetto. Pertanto, COM crea l'oggetto nell'appartamento principale del client e richiede che tutti gli altri appartamenti client accingano all'oggetto utilizzando proxy.
Quando un apartment a thread libero (modello apartment multithreading) in un client crea un server in-process threading apartment, COM avvia un thread "host" con modello apartment a thread singolo nel client. Questo thread host creerà l'oggetto e il puntatore all'interfaccia verrà sottoposto a marshalling nell'apartment a thread libero del client. Analogamente, quando un apartment a thread singolo in un client modello apartment crea un server in-process a thread libero, COM avvia un thread host a thread libero (apartment multithreading in cui verrà creato l'oggetto e quindi sottoposto a marshalling all'apartment a thread singolo client).
Nota
In generale, se si progetta un'interfaccia personalizzata in un server in-process, è necessario specificare anche il codice di marshalling per tale interfaccia in modo che COM possa effettuare il marshalling dell'interfaccia tra appartamenti client.
COM consente di proteggere l'accesso agli oggetti forniti da una DLL a thread singolo richiedendo l'accesso dallo stesso apartment client in cui sono stati creati. Inoltre, tutti i punti di ingresso della DLL (ad esempio DllGetClassObject e DllCanUnloadNow) e i dati globali devono sempre essere accessibili dallo stesso apartment. COM crea tali oggetti nell'appartamento principale del client, dando all'appartamento principale l'accesso diretto ai puntatori dell'oggetto. Le chiamate dagli altri appartamenti usano il marshalling interthread per passare dal proxy allo stub nell'appartamento principale e quindi all'oggetto. Ciò consente a COM di sincronizzare le chiamate all'oggetto . Le chiamate interthread sono lente, quindi è consigliabile riscrivere questi server per supportare più appartamenti.
Analogamente a un server in-process a thread singolo, è necessario accedere a un oggetto fornito da una DLL del modello apartment dallo stesso apartment client da cui è stato creato. Tuttavia, gli oggetti forniti da questo server possono essere creati in più appartamenti del client, pertanto il server deve implementare i punti di ingresso (ad esempio DllGetClassObject e DllCanUnloadNow) per l'uso multithreading. Ad esempio, se due appartamenti di un client tentano di creare due istanze dell'oggetto in-process contemporaneamente, DllGetClassObject può essere chiamato contemporaneamente da entrambi gli appartamenti. DllCanUnloadNow deve essere scritto in modo che la DLL non venga scaricata mentre il codice è ancora in esecuzione nella DLL.
Se la DLL fornisce una sola istanza della class factory per creare tutti gli oggetti, l'implementazione della class factory deve essere progettata anche per l'uso multithreading, perché sarà accessibile da più appartamenti client. Se la DLL crea una nuova istanza della class factory ogni volta che viene chiamato DllGetClassObject , la class factory non deve essere thread-safe.
Gli oggetti creati dalla class factory non devono essere thread-safe. Una volta creato da un thread, l'oggetto viene sempre eseguito tramite tale thread e tutte le chiamate all'oggetto vengono sincronizzate da COM. L'appartamento del modello apartment di un client che crea questo oggetto otterrà un puntatore diretto all'oggetto. Gli appartamenti client diversi dall'appartamento in cui è stato creato l'oggetto devono accedere all'oggetto tramite proxy. Questi proxy vengono creati quando il client effettua il marshalling dell'interfaccia tra i suoi appartamenti.
Quando un valore ThreadingModel DLL in-process è impostato su "Both", un oggetto fornito da questa DLL può essere creato e usato direttamente (senza un proxy) in appartamenti client a thread singolo o multithreading. Tuttavia, può essere utilizzato direttamente all'interno dell'appartamento in cui è stato creato. Per assegnare l'oggetto a qualsiasi altro appartamento, è necessario effettuare il marshalling dell'oggetto. L'oggetto DLL deve implementare la propria sincronizzazione e può essere accessibile da più appartamenti client contemporaneamente.
Per velocizzare le prestazioni per l'accesso a thread libero agli oggetti DLL in-process, COM fornisce la funzione CoCreateFreeThreadedMarshaler. Questa funzione crea un oggetto marshalling a thread libero che può essere aggregato con un oggetto server in-process. Quando un apartment client nello stesso processo richiede l'accesso a un oggetto in un altro apartment, l'aggregazione del gestore di marshalling a thread libero fornisce al client un puntatore diretto all'oggetto server, anziché a un proxy, quando il client effettua il marshalling dell'interfaccia dell'oggetto in un apartment diverso. Il client non deve eseguire alcuna sincronizzazione. Questo funziona solo all'interno dello stesso processo; Il marshalling standard viene usato per un riferimento all'oggetto inviato a un altro processo.
Un oggetto fornito da una DLL in-process che supporta solo il threading libero è un oggetto a thread libero. Implementa la propria sincronizzazione ed è possibile accedervi contemporaneamente da più thread client. Questo server non esegue il marshalling delle interfacce tra thread, quindi questo server può essere creato e usato direttamente (senza proxy) solo da appartamenti multithreading in un client. Gli appartamenti a thread singolo che lo creano accederanno tramite un proxy.
Argomenti correlati