2012-09-09 12 views
8

Per un programma AI C# uso una chiamata ricorsiva per trovare la migliore mossa successiva (utilizzando una matrice 30x30 per memorizzare lo stato attuale della scheda). Per ogni mossa che faccio, voglio vedere quale delle possibili mosse che posso fare dal nuovo stato della tavola sarà la migliore ... e così via fino a quando non raggiungerò una posizione di "fine del gioco" (non sono possibili ulteriori mosse in quel stato) o un timer interrompe il processo e non vengono effettuate ulteriori chiamate ricorsive (e viene restituita la "migliore" posizione nota). Questo solo per spiegare perché devo ricorrere alla ricorsione (non è la ricorsione della coda) e non posso usare un singolo stato (globale) della scheda, ma devo cercare tutti gli stati della scheda possibili dallo stato corrente.C'è un modo per controllare le dimensioni dello stack disponibili prima della chiamata ricorsiva? (C#)

(a volte) Ottengo un System.StackOverflowException. C'è un modo per controllare lo spazio di stack disponibile prima della prossima chiamata ricorsiva? Quindi potrei semplicemente restituire lo stato corrente come "la migliore posizione trovata finora" e non effettuare la prossima chiamata ricorsiva. Cioè quando lo stack disponibile diventa troppo piccolo, dovrebbe anche essere considerato come un caso base.

L'altra opzione, naturalmente, potrebbe essere quella di mettere semplicemente ogni chiamata ricorsiva in un blocco try..catch e gestire System.StackOverflowException usandolo come caso base?

+5

Ridisegnare il codice? Uno stackoverflow è un segno di un errore o di un codice errato (C#). È necessaria una quantità folle di chiamate ricorsive per attivare uno stackoverflow. Usa un linguaggio funzionale che supporti le code-call, come F #, se vuoi davvero farlo in questo modo. C# non è progettato per questo. – Dykam

+0

"Se si chiama un metodo ricorsivo o si pianifica di utilizzare molto spazio di stack, è necessario utilizzare il metodo RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup." - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.probeforsufficientstack.aspx – DavidO

risposta

1

Se si vuole davvero seguire questo percorso, è possibile utilizzare il metodo EnsureSufficientExecutionstack.

Come altri hanno sottolineato, a partire da .NET 2.0 si non può cattura un StackOverflowException, però, dalla documentazione MSDN si conosce il metodo precedente ha il seguente comportamento:

garantisce che lo spazio di stack rimanente è abbastanza grande per eseguire la funzione .NET Framework media .

Quando lo stack non è abbastanza grande secondo questo metodo allora un'eccezione InsufficientExecutionStackException che si può prendere .

+0

Hai provato? "Assicura che lo spazio rimanente nello stack sia sufficientemente grande per eseguire la funzione .NET Framework media". Nel caso dell'OP, lo spazio non può mai essere sufficiente - come avrebbe * saputo * questo metodo? –

+0

Ogni livello di ricorsione dovrebbe ricontrollare, no? – DavidO

+0

Questa parte proviene dalla documentazione MSDN, dovrei aggiungere un preventivo per questo, aggiornerò la risposta. Come ha sottolineato DavidO, il controllo dovrebbe essere eseguito in ogni fase per essere una soluzione valida. –

2

In realtà, il sistema espanderà le dimensioni dello stack in modo dinamico, se esaurisce lo spazio sullo stack esistente. Quindi, anche se tu, , potresti testare la dimensione dello stack,, non sarebbe importante.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx dettagli

Il sistema impegna pagine aggiuntive dalla memoria dello stack riservata in quanto sono necessari, fino a quando la pila raggiunge la dimensione riservata meno una pagina (che viene utilizzato come una pagina di guardia per evitare overflow dello stack) o il sistema è così basso sulla memoria che l'operazione fallisce"

che è dire che, prima che si verifichi la ricorsione, lo stack è taglia,. e se il ricorsione causa un overflow dello stack, lo stack è un nuova dimensione quando ciò è accaduto.

Dal momento che non è possibile catturare lo StackOverflowException, invece della ricorsione del terminale, è possibile utilizzare la ricorsione della coda. Il seguente collegamento fornisce alcune buon dettaglio sulla conversione terminale recusion in coda recusion: http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/

+0

"(A volte) Ottengo System.StackOverflowException." (Potrebbe essere utile spiegarlo.) – DavidO

+0

@DavidO, questo non vuol dire che nonostante l'aumento dello stack mentre la ricorsione è in corso, ha esaurito la memoria per espandere lo stack. –

+0

Dipende dalla posizione attuale della scheda. Se la risposta viene trovata abbastanza presto (il caso base viene trovato in anticipo), di solito non ho il problema. –

2

si potrebbe usare una coda + loop (Queue<TNode> + while (queue.MoveNext())) invece di ricorsione e limitare la dimensione della coda.

Oppure è possibile contare chiamate aperte al metodo e limitare la ricorsione in questo modo. (Conta le entrate e le uscite e non inserire la ricorsione se le voci - esiste> maxOpenCalls).

1

A partire da .NET 2 Non è possibile prendere StackOverflowException ...

L'unico modo per determinare la quantità del tuo stack è già utilizzato mezzi per utilizzare codice non sicuro, che vi consiglio vivamente di ... meglio usare un esplicito basato su heap Stack<T>.

Problemi correlati