2010-08-13 16 views
8

C'è un modo per far eseguire un delegato su un thread specifico?Richiamare un delegato su un thread specifico C#

Dire che ho:

CustomDelegate del = someObject.someFunction; 
Thread dedicatedThread = ThreadList[x]; 

posso avere uno sfondo coerente lungo filo esecuzione e richiamare i miei propri delegati su di esso ogni volta che ne ho bisogno. Deve essere lo stesso thread ogni volta.

[Edit]

Il motivo per cui voglio che sia in un thread dedicato è ora è che ho inten per eseguire il delegato su di esso e sospendere il filo dopo y millisecondi, e riprendere il filo quando corro un altro delegato su di esso. Vedo che questo non è possibile Avrò una coda delegato e lascerò che la funzione principale del thread legga ed esegua da essa.

Per chiarire con un esempio concreto, ho un sistema di gioco con un gruppo di thread giocatore. Vorrei che ogni giocatore avesse a disposizione gestori di eventi per eventi di gioco. Se i gestori di eventi impiegano troppo tempo, vorrei essere in grado di mettere in pausa quel particolare giocatore fino al prossimo evento sospendendo il suo thread.

Avendo così un thread dedicato su cui posso eseguire più gestori di eventi, posso mettere in pausa l'IA di un particolare giocatore nel caso in cui sia stato intercettato o abbia impiegato troppo tempo.

risposta

3

Penso che la soluzione migliore sia utilizzare gli oggetti Task e accodarli a un StaThreadScheduler con un singolo thread.

In alternativa, è possibile utilizzare ActionThread in Nito.Async per creare un thread normale con una coda incorporata di delegati Action.

Tuttavia, nessuno di questi affronterà direttamente un'altra necessità: la possibilità di "mettere in pausa" un'azione e continuare con un'altra. Per fare questo, è necessario cospargere "punti di sincronizzazione" in ogni azione e avere un modo per salvare il suo stato, ri-accodarlo e continuare con l'azione successiva.

Tutta questa complessità si avvicina molto a un sistema di pianificazione dei thread, quindi consiglio di fare un passo indietro e fare più di un re-design. È possibile consentire a ciascuna azione di essere accodata allo ThreadPool (si consiglia di fare in modo che ognuno di essi sia un oggetto Task). Avrai ancora bisogno di cospargere i "punti di sincronizzazione", ma invece di salvare lo stato e ri-metterli in coda, dovrai semplicemente metterli in pausa (bloccarli).

+0

Grazie per aver segnalato l'ActionThread, che sembra molto utile. Avevo bisogno di incapsulare un codice esterno su cui ho poco controllo in un thread. Tutto quello che ho è delegato al codice esterno. Se posso assicurare che l'oggetto si trova in un particolare thread, posso "mettere in pausa" quell'oggetto semplicemente sospendendo il thread. Non penso che il threadpool mi permetterà di "mettere in pausa" l'oggetto in modo piacevole. – Raynos

+0

Una parola di avvertimento: è possibile (anche probabile) causare deadlock accidentalmente sospendendo/riprendendo i thread. Se possibile, cambiare il codice esterno. Se ciò non è possibile, allora considera di usare le priorità dei thread invece di sospendere/riprendere. –

1

Normalmente, suggerirei di utilizzare solo il pool di thread o la classe BackgroundWorker, ma questi non garantiscono che il lavoro si verifichi su un determinato thread. Non è chiaro il motivo per cui ti interessa quale thread esegue i lavori, ma supponendo che in qualche modo sia importante ...

Si dovrebbe passare l'oggetto Delegate attraverso una sorta di memoria condivisa, come una coda. Il thread in background dovrebbe guardare questa coda, estrarne i delegati quando esistono e eseguirli.

Se si scopre che il pool di thread è accettabile per eseguire il codice, si può sempre utilizzare il metodo BeginInvoke del delegato a farlo:

// wrap your custom delegate in an action for simplicity ... 
Action someCode =() => yourCustomDelegate(p1, p2, p3, ...); 
// asynchronously execute the currying Action delegate on the threadpool... 
someCode.BeginInvoke(someCode.EndInvoke, action); 
2

Purtroppo non c'è davvero nulla di costruito per effettuare questa operazione su qualsiasi thread generico. Puoi farlo creando una classe che avvolge una Discussione e implementa ISynchonizeInvoke.

Un approccio semplice consiste nel creare una coda di elaborazione degli eventi sul thread dedicato come menzionato da LBushkin. Suggerisco di utilizzare una classe Queue<Action> e chiamare direttamente il delegato dell'Azione. È possibile eseguire la maggior parte delle attività che è necessario utilizzando le azioni anonime dei delegati.

Infine, proprio come una parola di avvertimento, vorrei suggerire di utilizzare un semaforo o EventWaitHandle invece di Thread.Sleep sul thread dedicato. È decisamente più facile che eseguire il ciclo di background più e più volte quando non è necessario.

+0

Grazie, avevo intenzione di eseguire il ciclo di background più e più volte. Analizzerò un gestore di attesa dell'evento – Raynos

+1

Sono d'accordo con l'avviso su 'Thread.Sleep'; tuttavia, l'op dovrebbe implementare 'SynchronizationContext' piuttosto che l'obsoleto' ISynchronizeInvoke'. –

0

Per i thread creati, è possibile specificare solo il delegato ThreadStart al momento della creazione. Non è prevista l'iniezione di un delegato diverso in un thread creato. Il pool di thread è diverso in quanto consente di inviare delegati a thread creati in precedenza che vengono avviati per conto dell'utente.

Non è chiaro quale problema si stia tentando di risolvere. Cosa stai cercando di realizzare (o evitare) cercando di eseguire più delegati su un thread?