+ Accorgersi del Deadlock
Come accorgersi quando un deadlock è in corso ?
Mantenere il grafo di allocazione dei lock sulle istanze man mano che vengono acquisiti a run-time e cercare cicli nel grafo è una possibilità ... che non viene quasi mai utilizzata.
Quasi sempre si preferisce imporre un time-out nella acquisizione del lock a un'istanza. Quando scatta il time-out probabilmente è un deadlock. Ad esempio anche il Db Oracle fa cosi.
L'istruzione per acquisire un lock con timeout in .NET è Monitor.TryEnter(istanza, timeout)
+ Scegliere il time-out
Se è troppo breve potrebbe scattare il timeout a causa di una operazione un po più lunga del solito senza che ci sia alcun deadlock in corso. Se è troppo lungo il sistema potrebbe restare congelato per molto tempo senza di reagiera al deadlock in corso.
Java e .NET a run-time hanno a disposizione molte informazioni sul codice in esecuzione e in particolare lo stack-trace. Basta salvare una copia dello stack-trace prima di acquisire il lock di una istanza cosi quando c'è un time-out si può loggare lo stack-trace del thread in time-out (il richiedente del lock) e anche lo stack-trace salvato in precedenza (il detentore del lock).
Guardandoli con il codice sorgente il programmatore può individuare quando c'è un ciclo nel grafo di allocazione (ed eventualmente modificare il codice per evitare che si possa ripetere) o quando non c'è deadlock e invece è stata solo una operazione un po lunga.
+ Implementare il Retry
La parte più difficile è scrivere il codice in modo che sia possibile ripetere l'operazione dopo che c'è stato un timeout. L'operazione è comunciata con una chiamata a un metodo che quindi ha fatto chiamate a altri metodi di altre istanze in un punto di questa sequenza (uno qualunque tra quelli dove viene acquisito un lock) c'è stato il timeout.
Per ripetere l'operazione è necessario annullare tutte le operazioni già eseguite e riportare le istanze allo stato iniziale. E' un concetto molto simile a quello di transazione, l'esecusione deve avere le medesime proprietà ACID: http://c2.com/cgi/wiki?AtomicConsistentIsolatedDurable .
2 possibili modi di implementarlo
Usare il pattern Command Object per eseguire i comandi sia per l'undo che il redo: dal Portland Pattern Repository http://c2.com/cgi/wiki?CommandObject e dal wiki http://wiki.ugidotnet.org/default.aspx/UGIdotNETWiki/PatternCommand
Usare il pattern Memento per memorizzare lo stato iniziale degli oggetti e riprestinarlo in caso di time-out: dal wiki http://wiki.ugidotnet.org/default.aspx/UGIdotNETWiki/PatternMemento
Tags : Progettazione Software |