2013-03-12 13 views
15

Ho avuto un'intervista solo 5 minuti indietro, non ho risposto a 3 domande, qualcuno potrebbe aiutarmi per favore.Come trovare deadlock e prevenirlo in C#

Domanda:

Come cercare scenari deadlock in funzione di applicazioni multithread e impedirlo?

risposta che ho dato:

ho dato la definizione di stallo e blocco, mutex, monitor, semaforo. Mi ha detto, che questi sono strumenti, ma come cercare uno scenario di stallo, come, perché quando usiamo questi strumenti alla cieca, il costo delle prestazioni, ha detto :(

Si prega di aiutarmi a capire questo.

+3

Si dovrà analizzare i modelli di bloccaggio ... Non riesco a pensare a una risposta molto compatto. –

+2

Stava chiedendo un modo generico per verificare un deadlock? Tutto quello che so è guardando il codice e usando un po 'di intelligenza ... – TheKingDave

+0

Per prevenire i deadlock, devi usare un'implementazione lockfree. Se è assolutamente necessario mantenere i blocchi, è necessario assicurarsi che quando sono richiesti più blocchi, gli oggetti bloccati siano bloccati in un ordine ben definito. – Nolonar

risposta

5

Gli strumenti di analisi delle prestazioni possono essere anche utili per identificare gli deadlock, tra gli altri. Questa domanda fornirà alcune informazioni su questo argomento: C#/.NET analysis tool to find race conditions/deadlocks.

L'analisi visiva del codice e l'uso corretto dei blocchi è utile anche (dovresti essere in grado di rilevare potenziali problemi nel codice durante l'ispezione), ma può essere molto difficile per applicazioni complesse. A volte i deadlock sono visibili solo quando si esegue il codice, non semplicemente controllando il codice.

Non conosco troppo il vostro intervistatore. Alcuni potrebbero voler vedere quanto sai di standard di chiusura/guida, alcuni potrebbero voler vedere se sai come usare i tuoi strumenti, alcuni potrebbero volere entrambi. Nell'azienda in cui lavoro, ad esempio, l'uso di strumenti (specialmente quelli che già possediamo e utilizziamo) è molto apprezzato. Ma ciò non implica che non si dovrebbero avere le abilità che impedirebbero di bloccare i blocchi di codice in primo luogo.

Il blocco di un elemento solo per motivi di blocco influisce sulle prestazioni, poiché i thread si attendono reciprocamente. È necessario analizzare il flusso di lavoro per determinare ciò che deve essere bloccato, quando, con quale tipo di blocco (semplice lock o forse un Readerwriterlockslim). Ci sono molti modi tipici per prevenire il deadlock.

Ad esempio quando si utilizza Readerwriterlockslim è possibile utilizzare un timeout per evitare situazioni di stallo (se si aspetta a molto, è abord acquisendo la serratura) http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

if (cacheLock.TryEnterWriteLock(timeout)) 
{ 
... 
} 

E si dovrebbe essere in grado di suggerire tali timeout.

A una domanda del genere, mi aspetterei almeno una menzione del classico caso di deadlock, come l'uso scorretto dei blocchi annidati (dovresti saperlo, puoi evitarli, perché sono cattivi, ecc.).

Il soggetto è molto grande ... puoi andare avanti all'infinito. Ma senza definizioni. Sapere cos'è un lucchetto e sapere di usare serrature/semafori/mutex in applicazioni multi-threding su larga scala sono 2 cose diverse.

+0

Grazie Coral, questa è una nuova conoscenza per me sulla conoscenza degli strumenti per l'analisi delle prestazioni, daremo un'occhiata a quel link :) Grazie ancora ... Saluti – Learner

0

Il più semplice la soluzione per questo problema sarebbe quella di dormire/aspettare sempre con un timeout abbastanza grande.Se quel timeout accade capisci che qualcosa è durato più a lungo di quello che dovrebbe avere e hai una buona possibilità di un deadlock o un altro bug

Mutex m; // similar overloads exist for all locking primitives 
if (!m.WaitOne(TimeSpan.FromSeconds(30))) 
    throw new Exception("Potential deadlock detected."); 

Quando WaitOne restituisce false avrà aspettato per 30 secondi e il blocco Non sarei stato rilasciato. Se sai che tutte le operazioni bloccate dovrebbero essere completate entro millisecondi (in caso contrario, basta aumentare il timeout), allora questa è un'ottima indicazione che qualcosa è andato male.

+0

Come fa a capire la differenza tra deadlock e fame ? – Nolonar

+0

Ciao Hnagis, grazie per la risposta, temo di non aver capito cosa dici :(Sono nuovo del multithreading :(Mi dispiace, sarà fantastico se riesci a riformulare quello che stanno cercando di dire :( – Learner

+1

Sta impostando un timeout su un mutex. Ciò significa che aspetterà fino a 30 secondi prima di continuare. Se scade, la funzione ritorna falsa e così può sapere che nessuno ha pulsato il mutex. Con un timeout sufficientemente lungo questo * potrebbe * significare deadlock. Potrebbe essere la parola chiave qui. Non sempre significa stallo. – devshorts

4

Penso che l'intervista ti stia facendo una domanda trabocchetto. Se potessi usare l'analisi statica per evitare un deadlock ... nessuno avrebbe un deadlock!

Personalmente, quando cerco lo stallo, comincio a trovare funzioni in cui la sezione critica si estende oltre la chiamata di funzione. Per esempio

void func(){ 
    lock(_lock){ 
     func2(); 
    } 
} 

Non è molto chiaro quello che sta facendo func2. Forse invia un evento sullo stesso thread, il che significherebbe che l'evento fa ancora parte della sezione critica. Forse si blocca quindi su un blocco diverso. Forse si invia al threadpool e non è più rientrante perché è ora su un thread diverso! Questi tipi di luoghi sono dove puoi iniziare a vedere gli scenari di stallo: quando hai più posizioni di blocco non rientranti.

Altre volte, quando si tracciano scenari di deadlock, faccio il backtrack e cerco di trovare dove sono stati creati tutti i thread. Dò pensiero a ciascuna funzione e dove può effettivamente essere in esecuzione. Se non si è sicuri, può anche essere utile aggiungere la registrazione per registrare da dove proviene la chiamata alla funzione.

È inoltre possibile evitare i deadlock utilizzando strutture di dati senza blocchi (ma richiedono comunque altrettanti usi). Si desidera ridurre al minimo l'accesso alla struttura senza blocco perché ogni volta che si accede a esso può cambiare.

Come menzionato in un'altra risposta, è possibile utilizzare i mutex con timeout, ma non è garantito che funzionino sempre (cosa succede se il codice deve funzionare più a lungo del timeout?). È stato menzionato in un altro commento che questo è forse ciò che l'intervistatore stava chiedendo. Trovo che nella produzione questa non sia davvero una buona idea. I timeout variano in continuazione, forse c'è voluto più tempo del previsto per correre e colpire un timeout. Penso sia meglio lasciarlo a un punto morto, prendere una discarica di processo, quindi trovare esattamente cosa tenesse i lucchetti e risolvere il problema. Naturalmente, se i tuoi requisiti aziendali non lo consentono, puoi utilizzarlo come parte di una strategia di codifica difensiva insieme a scelte di posizionamento intelligenti.

Non sono d'accordo con la tua intervista che blocca sempre aggiungere un enorme problema di prestazioni. Serrature/mutex/ecc. Non contestati prima prova come spinlock prima di passare al sistema operativo e gli spinlock sono economici.

In generale, il modo migliore per evitare un deadlock è capire il flusso del programma. Ogni volta che introduci un nuovo oggetto di blocco, pensa a dove è usato e a cosa lo usa lungo la catena.

+0

Grazie di cuore per la spiegazione, è una grande quantità di informazioni per me :) Saluti – Learner

6

Sembra che tu abbia avuto problemi nello spiegare come si possono verificare deadlock e come possono essere prevenuti.

deadlock si verifica quando ciascuno dei due (minimo due) thread tenta di acquisire un blocco su una risorsa già bloccata da un altro. Thread 1 bloccato su Risorse 1 tenta di acquisire un blocco su Risorsa 2. Allo stesso tempo, Thread 2 ha un blocco su Risorsa 2 e tenta di acquisire il blocco su Risorsa 1. Due thread non abbandonano mai i blocchi, quindi si verifica un DEADLOCK .

Il modo più semplice per evitare il deadlock è utilizzare un valore di timeout. La classe Monitor (system.Threading.Monitor) può impostare un timeout durante l'acquisizione di un blocco.

Esempio

try{ 
    if(Monitor.TryEnter(this, 500)) 
    { 
     // critical section 
    } 
} 
catch (Exception ex) 
{ 

} 
finally 
{ 
    Monitor.Exit(); 
} 

Read More

+0

Grazie a te, Garreh, che mi aiuta, esplorerò di più su questo :) Cheers – Learner

+0

Solo per curiosità, come mai che cosa stai usando catch after if block? O questa è solo una specie di pseudocodice. Su winCE (.net compacFframework), è possibile passare solo oggetto senza timeout in Monitor.TryEnter. C'è un modo per scrivere la propria implementazione con timeout? –

+0

@RomaBorodov Sembra che ho lasciato fuori il tentativo. Buona pesca! Fisso. –

Problemi correlati