Domanda

Questo è attivato da un'altra domanda.

In particolare, ho una classe com del processo, definita in Registro CLSID come avere un ThreadingModel di Both.

Il nostro processo attiva questo oggetto attraverso CoCreateInstance (non CoCreateInstanceEx, se anche questo è importante per un server DLL in-Proc)

Dato un modello di threading di Bothe date le regole elencate in Documenti:

Threading model of server | Apartment server is run in
------------------------------------------------------
Both                      | Same apartment as client

e dato ciò che Hans scrive nell'altra risposta:

... Il marshalling si verifica quando la chiamata del cliente deve essere effettuata su un thread diverso. ... può accadere quando il thread -model specificato nell'elemento ComClass lo richiede. In altre parole, quando l'oggetto COM è stato creato su un thread ma viene chiamato su un altro e il server non è sicuro.

La mia conclusione provvisoria sarebbe che un tale oggetto lo farà mai Hai bisogno di un marshalling implicito delle chiamate alle sue interfacce, poiché l'oggetto vivrà sempre nello stesso appartamento del suo cliente.

È corretto, anche se il processo client è in esecuzione come Sta?

È stato utile?

Soluzione

Sì, potrebbe esserci un marshalling.

Se il cliente della tua classe COM è in esecuzione in uno STA e tenti di invocare la tua classe da un altro appartamento, dovrà fare il maresciallo all'appartamento in cui è stato creato.

La terminologia COM può essere davvero confusa. Quando ti riferisci a un "client" in questo caso, ti riferisci davvero a un thread, non all'intera applicazione (come implicherebbe).

Both Significa solo che il modello di threading del server è conforme al client che lo istanzia. Cioè, quando installi la tua classe, assume il modello di threading del thread su cui è stato creato. Dal momento che stai istanzionando il server in uno STA, il tuo server utilizzerà STA, il che significa che può essere invocato solo sul thread che lo ha creato; Se un altro thread cerca di invocarlo, si è creato al thread su cui è stato creato.

Altri suggerimenti

Non posso fare a meno di pubblicare questo, anche se non è una risposta diretta alla domanda.

C'è un brillante articolo di MSKB di The Golden Ages of Com: Info: Descrizioni e funzionamento dei modelli di threading ole. Ancora lì e ha tutte le informazioni pertinenti. Il punto è che non dovresti preoccuparti se ci sia il maresciallo o no, se segui le regole. Basta registrare il tuo oggetto come ThreadingModel=Both, aggrega il maresciatore a filo libero con CoCreateFreeThreadedMarshaler, e essere fatto. Com farà il marshalling se necessario, nel miglior modo possibile. A seconda del modello di appartamento del cliente, il codice client può ricevere il puntatore diretto all'interfaccia, se segue anche le regole.

Qualsiasi interfaccia "aliena" che potresti ricevere quando viene chiamato un metodo dell'interfaccia, sarà valida nell'ambito della chiamata, perché rimani sulla stessa discussione. Se non hai bisogno di archiviarlo, è tutto ciò che conta.

Se comunque devi memorizzare nella cache l'interfaccia "aliena", il modo giusto di farlo sarebbe quello di archiviarla usando CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

Per immagazzinarlo:

  • Inserire la sezione critica;
  • chiamata CoMarshalInterThreadInterfaceInStream e conservare il IStream puntatore in un campo membro;
  • Lasciare la sezione critica;

Per recuperarlo

  • Inserire la sezione critica;
  • chiamata CoGetInterfaceAndReleaseStream Per recuperare l'interfaccia
  • chiamata CoMarshalInterThreadInterfaceInStream e riporlo di nuovo come IStream Per qualsiasi uso futuro
  • Lasciare la sezione critica;
  • Utilizzare l'interfaccia nell'ambito della chiamata corrente

Per rilasciarlo:

  • Quando non hai più bisogno di mantenerlo, rilasciare il memorizzazione IStream (all'interno della sezione critica).

Se l'oggetto "alieno" è anche a un thread libero e le cose stanno accadendo all'interno dello stesso processo, probabilmente avrai a che fare con un puntatore di interfaccia diretta dopo CoGetInterfaceAndReleaseStream. Tuttavia, non dovresti fare alcuna ipotesi e non devi davvero sapere se l'oggetto con cui si tratta è l'oggetto originale o un proxy com marshaller.

Questo può essere leggermente ottimizzato utilizzando CoMarshalInterface con MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData invece di CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, per sgrassare la stessa interfaccia quante volte necessario senza rilasciare il flusso.

Sono possibili scenari di memorizzazione nella cache più complessi (e forse più efficienti), coinvolgendo la conservazione locale. Tuttavia, credo che sarebbe un overkill. Non ho fatto alcun tempismo, ma penso che il sovraccarico di CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreamè davvero basso.

Detto questo, se hai bisogno di mantenere uno stato che memorizza qualsiasi risorsa o oggetti che potrebbero richiedere affinità del thread, oltre alle interfacce COM di cui sopra, tu non dovrebbe Segna il tuo oggetto come ThreadingModel=Both o aggregare l'FTM.

Sì, il marshalling è ancora possibile. Un paio di esempi:

  1. L'oggetto viene istanziato da un thread MTA e quindi inserito in un appartamento MTA e quindi il suo puntatore viene passato in qualsiasi thread STA e quel thread STA chiama metodi dell'oggetto. In questo caso un thread STA può accedere all'oggetto solo tramite marshalling.

  2. L'oggetto viene istanziato da un filo STA e quindi inserito in un appartamento STA appartenente a quel thread e quindi il suo puntatore viene passato in un altro thread STA o in un thread MTA. In entrambi i casi tali thread possono accedere all'oggetto solo tramite marshalling.

In effetti non ci si può aspettare che nessun marshalling solo nei seguenti due casi:

  1. L'oggetto viene istanziato da un thread MTA e quindi accessibile solo dai thread MTA, sia quello che istanziava l'oggetto e tutti gli altri thread MTA dello stesso processo.
  2. L'oggetto è istanziato da un thread STA e quindi accessibile solo da quel thread

E in tutti gli altri casi marshalling entrerà in gioco.

ThreadingModel = Entrambi significa semplicemente che l'autore del server COM può dare una garanzia che il suo codice sia thread-safe ma non può dare la stessa garanzia che Altro Il codice che non ha scritto verrà chiamato in modo da thread-safe. Il caso più comune per ottenere tale codice estero da eseguire è tramite callbacks, i punti di connessione sono l'esempio più comune (solitamente chiamato "eventi" in Client Runtimes).

Quindi, se l'istanza del server è stata creata in una STA, il programmatore client si aspetterà che gli eventi funzionino su quello stesso thread. Anche se un metodo server che spara un tale evento è stato chiamato da un altro thread. Ciò richiede che quella chiamata venga marshalling.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top