2010-12-12 14 views
5

ho questo semplice codice:problemi di threading in C# da processo esterno

public void Run() 
{ 
    var invokerThread = new Thread(new ThreadStart(RunOnBackground)); 
    invokerThread.Start(); 
} 

private void RunOnBackground() 
{ 
    Trace.WriteLine("hi"); 
    ... 
} 

Purtroppo durante l'esecuzione di questo codice (da processo di terze parti) il filo non realmente eseguito. O in Process Explorer e nel debugger VS vedo che il thread è stato creato e il suo stato è "In esecuzione".

L'appartamento del thread principale è STA e ho provato sia STA che MTA su thread interno.

Quando aggiungo al metodo Run() al termine invokerThread.Join();, il thread viene eseguito. Ma poi di nuovo non aiuta davvero.

Cosa mi manca?

Edit: Ecco qualche informazione in più per quanto riguarda il codice di hosting -

Run() metodo viene chiamato tramite l'interoperabilità COM da un processo che è anche riuscito assembly eseguibile (l'interoperabilità ragione COM viene utilizzato è perché tutti gli altri componenti del il sistema è nativo).

Il metodo RunOnBackground() include un po 'più di codice dopo la traccia e in genere la sua esecuzione dura tra 10 e 20 secondi, incluso l'avvio di un altro processo e in attesa della sua conclusione. Inoltre ho alcune altre aree nel codice in cui scrivo alcune informazioni di debug su Trace. Durante il debug del codice, Run() viene eseguito come al solito e dopo invokerThread.Start(); lo stato di invokerThread è "In esecuzione" (anche se i punti di interruzione all'interno del metodo RunOnBackground() non si fermano).

Quando aggiungo invokerThread.Join() alla fine del metodo Run() il debugger va a RunOnBackground()dopo il Join().

+0

Non si dovrebbe mostrare un MessageBox all'interno del thread di lavoro. Modifica per utilizzare Trace –

+0

Aggiornamento del codice. Ancora non funziona. Per favore, vedi la risposta che ho scritto a Martin. – Aaron

+0

Hai detto: "Sfortunatamente quando si esegue questo codice (da processi di terze parti) il thread non viene eseguito realmente". Come stai esattamente "eseguendo questo codice"? –

risposta

3

Mancano alcune informazioni importanti su cosa RunOnBackground() fa davvero. In caso contrario, si tratta di una buona corrispondenza per ciò che accade quando si utilizzano oggetti COM threaded apartment su un thread di lavoro. COM esegue automaticamente il marshalling di qualsiasi chiamata di metodo su un oggetto di questo tipo dal thread di lavoro al thread STA su cui è stato creato.

Questo può funzionare solo quando il thread STA rispetta i requisiti di filettatura STA. Deve pompare un loop di messaggi e non può bloccare.L'interruzione di tali regole rende molto probabile il deadlock, la chiamata al thread di lavoro non può essere completata finché il thread STA non invia la chiamata con marshalling. Un segno sicuro che questo è ciò che sta succedendo è vedere Thread.Join() risolvere il problema. Pompa internamente un loop di messaggi nel CLR quando viene chiamato su un thread STA.

Per diagnosticare ciò, è necessario Debug + Windows + Thread per vedere a cosa sta bloccando quel thread di lavoro. Se la mia ipotesi è giusta, sarà sepolto nel profondo del codice dell'impianto idraulico COM, in attesa che la chiamata al marshall sia completata. È possibile vederlo solo abilitando il debug del codice non gestito e configurando il Microsoft Symbol Server in modo da ottenere il debug dei simboli per il codice dell'impianto idraulico e ottenere una traccia dello stack affidabile.

Risolvere questo problema sarà difficile. Non è possibile capovolgere magicamente un interruttore ed eseguire il codice su un thread quando ha dichiarato esplicitamente che non supporta il multi-threading. È indispensabile creare l'istanza dell'oggetto COM sullo stesso thread che chiama i suoi metodi. E quel thread deve essere un thread STA. Controlla questo sample code per l'approccio. Se non controlli la creazione dell'oggetto COM, allora sei bloccato.

+0

Hans, grazie per la breve risposta. Hai scritto che "... vedi a quale thread di lavoro si blocca". In realtà durante il debug vedo che dopo Start() lo stato del thread di lavoro è cambiato in "in esecuzione". Il metodo RunOnBackground() chiama altri metodi che uno di loro avvia un altro processo e attende la sua uscita, ma ho anche provato a semplificare lo scenario commentando tutto all'interno del metodo RunOnBackground() e scrivendo alcuni semplici Trace.Write() e alcuni compiti (come var x = 1;). – Aaron

0

Posso dire qualcosa di stupido, ma ecco quello che ho visto in MSDN Threads.

Guarda la sezione degli esempi alla fine.

L'output dell'esempio è interessante, è possibile vedere che il thread creato e avviato inizia a essere eseguito solo quando il thread principale esegue uno Sleep (0) o un Thread.Join().

Sembra che sia esattamente quello che ti succede, vero?

Forse provare con uno Sleep (0) sul thread principale per avviare davvero il thread di lavoro.

Un'altra soluzione alternativa sarebbe utilizzare BackGroundWorker.

Come dice il nome, funziona sullo sfondo ed è davvero facile da usare. Potrebbe essere di grande utilità per te.

+0

Provato con Thread.Sleep(). Non aiuta Anche BackgroundWorker non viene avviato. – Aaron