Domanda

imbatte in quello che appare a prima vista come un MT-problema, ma sto cercando di capire in dettaglio il modello STA utilizzato da COM +.

In effetti, ho un retaggio componente COM +, scritto in VB6, che chiama in un nativo (vale a dire, non-COM) DLL Win32 scritto in C ++.

Avendo alcuni problemi intermittenti (e impossibili da riprodurre in fase di test) con esso, ho aggiunto un po 'di codice di debug per scoprire cosa stava succedendo e ha scoperto che quando si verificano i problemi, ho avuto messaggi intercalate nel file di log - in modo implicava che il DLL veniva chiamato da due fili contemporaneamente.

Ora la registrazione va a un file per ogni thread in base a _getpid () e GetCurrentThreadId (), così sembra che quando il codice nella ++ DLL C si chiama, è sempre chiamato due volte sullo stesso thread allo stesso tempo. La mia comprensione di STA dice suggerisce che questo potrebbe essere il caso come COM marshalling le singole istanze di oggetti su un singolo thread sospende e riprende l'esecuzione a volontà.

Unfortuantly non sono sicuro dove andare da qui. Sto leggendo che dovrei essere chiamando CoInitialiseEx () in DllMain () per dire COM che questo è un DLL STA, ma altri posti dicono che questo è valido solo per le DLL COM e non avrà alcun effetto in una DLL nativa. L'unica altra opzione è quella di avvolgere le parti del DLL le sezioni come critiche per serializzare l'accesso (prendendo colpo qualunque prestazione che ha sul mento).

ho potuto provare e rielaborare la DLL, ma non c'è stato o globali Vars condiviso - tutto è in variabili locali quindi in teoria ogni chiamata dovrebbe avere il proprio stack, ma mi chiedo se il modello STA è fondamentalmente avendo qualche strano effetto su questo e solo rientrando nella DLL già caricata nello stesso punto di ingresso come un'altra chiamata. Unfortuantly, non so come dimostrare o verificare questa teoria.

Le domande fondamentalmente sono:

  1. Quando uno STA componente COM + chiama una DLL nativa, non c'è niente nel modello STA a impedire il "filo" attivo sospensione e controllo essendo passata sopra ad un altro "filo" nel mezzo di una chiamata DLL?
  2. È CoInitialiseEx () il modo giusto per risolvere questo, o no?
  3. Se nessuno dei due (1) o (2) sono "buoni" ipotesi, cosa sta succedendo?
È stato utile?

Soluzione

In un server COM appartamento threaded, ogni istanza della classe COM è garantito per essere accessi da un unico filo. Questo mezzo l'istanza è sicuro thread. Tuttavia, molti casi possono essere create simultaniously, utilizzando thread differenti. Ora, per quanto riguarda il server COM è interessato, la DLL nativa non deve fare nulla di speciale. Basta pensare a kernel32.dll, che viene utilizzato da ogni eseguibile -? Non mi inizializzare COM quando viene utilizzato da un server COM

Dal punto di vista DLL, è necessario assicurarsi che sei thread-safe, come diverse istanze possono chiamare allo stesso tempo. STA non vi proteggerà in questo caso. Dal momento che tu dici non si utilizza le variabili globali, posso solo supporre il problema è altrove, e succede solo a dimostrare le circostanze che sembrano indicare la roba COM. Sei sicuro di non avere alcuni problemi di memoria C ++ vecchi pianura?

Altri suggerimenti

Ho il sospetto che il tuo problema è che da qualche parte nel profondo della chiamata DLL, ha fatto una chiamata COM in uscita in un altro appartamento (un altro thread nello stesso processo, o di un oggetto nel MTA, o un altro processo del tutto). COM consente un thread STA in attesa del risultato di una chiamata in uscita per ricevere un'altra chiamata in entrata, elaborarlo in modo ricorsivo. E 'previsto solo per le conversazioni in corso tra gli stessi oggetti - cioè A chiama B, B chiama Una schiena, A chiama B di nuovo - ma può ricevere chiamate da altri oggetti se hai distribuito un puntatore a più client, o il client ha condiviso il puntatore di interfaccia a un altro client. In generale si tratta di una cattiva idea di distribuire i puntatori di interfaccia per un oggetto a thread singolo per più thread client, in quanto avranno resta che attendere per l'altro. Creare un oggetto operaio per thread.

COM non può sospendere e riprendere l'esecuzione a piacimento su qualsiasi thread - una nuova chiamata in arrivo su un thread STA può arrivare solo attraverso la pompa messaggio. Quando 'bloccato' in attesa di una risposta, il filo è effettivamente STA pompando messaggi, controllando con il Message Filter (vedi IMessageFilter) se il messaggio deve essere gestito. Tuttavia, gestori di messaggi non devono effettuare una nuova chiamata in uscita - se lo fanno COM restituirà un errore RPC_E_CANTCALLOUT_INEXTERNALCALL ( "E 'illegale chiamare fuori mentre filtro dei messaggi all'interno")

Problemi analoghi potrebbero verificarsi se si dispone di una pompa di messaggio (GetMessage / DispatchMessage) in qualsiasi punto all'interno della DLL nativa. Ho avuto problemi con DoEvents di VB nelle procedure di interfaccia.

CoInitializeEx dovrebbe essere chiamato solo dal creatore di un filo, perché solo loro sanno che cosa il loro comportamento di pompaggio messaggio sarà. E 'probabile che se si tenta di chiamare in DllMain sarà semplicemente fallire, come la DLL nativa è chiamata in risposta ad una chiamata COM, in modo che il chiamante deve essere in ultima analisi, già chiamato CoInitializeEx sul filo, al fine di effettuare la chiamata. Farlo nella notifica DLL_THREAD_ATTACH, per le discussioni di recente creazione, potrebbe funzionare superficialmente, ma sì che il programma di malfunzionamento se i blocchi COM quando dovrebbe pompare e viceversa.

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