Devo occuparmi delle condizioni di gara che quasi certamente non hanno possibilità di verificarsi?

52

Consideriamo qualcosa come un'applicazione GUI in cui il thread principale sta aggiornando l'interfaccia utente quasi istantaneamente, e qualche altro thread sta interrogando i dati sulla rete o qualcosa che è garantito per richiedere 5-10 secondi per completare il lavoro.

Ho ricevuto molte risposte diverse per questo, ma alcune persone dicono che se si tratta di una condizione di competizione di impossibilità statistica, non preoccuparti affatto, ma altri hanno detto che se c'è anche un 10 -53 % (Non scherzo sui numeri, questo è quello che ho sentito) di qualche magia voodoo che si verifica a causa delle condizioni di gara, ottieni sempre / rilascia blocchi sul thread che ne ha bisogno.

Quali sono i tuoi pensieri? È una buona pratica di programmazione gestire le condizioni di gara in tali situazioni statisticamente impossibili? o sarebbe del tutto inutile o addirittura controproducente aggiungere più linee di codice per ostacolare la leggibilità?

    
posta l46kok 10.08.2015 - 00:38
fonte

16 risposte

136

Se è veramente un evento 1 in 10 ^ 55, non ci sarebbe bisogno di codificarlo. Ciò implicherebbe che se tu facessi l'operazione 1 milione di volte al secondo, avresti un bug ogni 3 * 10 ^ 41 anni che è, approssimativamente, 10 ^ 31 volte l'età dell'universo. Se la tua applicazione ha un errore solo una volta ogni mille miliardi di miliardi di anni dell'universo, probabilmente è abbastanza affidabile.

Tuttavia, scommetto molto pesantemente che l'errore non è affatto vicino a quello improbabile. Se riesci a concepire l'errore, è quasi certo che si verificherà almeno occasionalmente, quindi per cominciare valga la pena scrivere correttamente. Inoltre, se si codificano i thread correttamente all'inizio in modo da ottenere e rilasciare i blocchi in modo appropriato, il codice è molto più gestibile in futuro. Non devi preoccuparti quando stai apportando una modifica che devi riesaminare tutte le potenziali condizioni di gara, ricalcolare le loro probabilità e assicurarti che non si ripeteranno.

    
risposta data 17.08.2012 - 05:47
fonte
69

Dal punto di vista costi-benefici, dovresti scrivere un codice aggiuntivo solo quando ottieni un vantaggio sufficiente.

Ad esempio, se la cosa peggiore che succederebbe se un thread sbagliato "vinca la gara" è che l'informazione non verrà visualizzata, e l'utente dovrebbe fare clic su "Aggiorna", non preoccuparsi di sorvegliare le condizioni della gara : dover scrivere molto codice non vale la pena di aggiustare qualcosa di insignificante.

D'altra parte, se la condizione della competizione può comportare trasferimenti di denaro errati tra conti bancari, devi proteggerti dalle condizioni della gara, indipendentemente da quanto codice devi scrivere per risolvere questo problema.

    
risposta data 17.08.2012 - 05:50
fonte
45

Trovare una condizione di gara è la parte difficile. Probabilmente hai passato quasi tutto il tempo a scrivere questa domanda in quanto ti avrebbe portato a risolverlo. Non è che lo rende molto meno leggibile. I programmatori si aspettano di vedere il codice di sincronizzazione in tali situazioni, e in realtà potrebbero sprecare più tempo chiedendosi perché non è lì e se aggiungerlo risolverà il bug non correlato.

Per quanto riguarda le probabilità, verrai sorpreso. L'anno scorso ho avuto un bug relativo alle condizioni della gara che non sono riuscito a riprodurre con migliaia di tentativi automatici, ma il un sistema di un cliente l'ha visto tutto il tempo. Il valore aziendale di spendere 5 minuti per risolverlo ora, rispetto alla possibile risoluzione di un bug "impossibile" nell'installazione di un cliente, rende la scelta un gioco da ragazzi.

    
risposta data 17.08.2012 - 06:37
fonte
27

Ottieni e rilascia le serrature. Le probabilità cambiano, gli algoritmi cambiano. È una cattiva abitudine entrare e quando qualcosa va storto non devi fermarti e chiediti se hai sbagliato le quote ...

    
risposta data 17.08.2012 - 05:53
fonte
13

and some other thread is polling data over the network or something that is guaranteed to take 5-10 seconds to finish the job.

Finché qualcuno non introduce un livello di memorizzazione nella cache per migliorare le prestazioni. All'improvviso quell'altro battistrada termina quasi all'istante e la condizione della gara si manifesta più spesso.

Se fosse successo esattamente qualche settimana fa, sono stati necessari circa 2 giorni di sviluppo completi per trovare il bug.

Sempre corregge le condizioni di gara se le riconosci.

    
risposta data 17.08.2012 - 15:12
fonte
8

Semplice vs corretto.

In molti casi, la semplicità supera la correttezza. È un problema di costi.

Inoltre, le condizioni di gara sono cose sgradevoli che tendono a non obbedire alle statistiche semplici. Tutto va bene fino a quando altre sincronizzazioni apparentemente non correlate causano all'improvviso la tua condizione di gara per metà del tempo. A meno che tu non accenda i log o esegua il debug del codice, naturalmente.

Un'alternativa pragmatica alla prevenzione di una condizione di competizione (che può essere complicata) può essere quella di rilevarla e registrarla (bonus per non riuscire in modo difficile e precoce). Se non succede mai, hai perso poco. Se effettivamente accade, hai una solida giustificazione per impiegare il tempo extra a risolverlo.

    
risposta data 17.08.2012 - 06:46
fonte
7

Se la tua condizione di competizione è legata alla sicurezza, devi sempre codice per impedirlo.

Un esempio comune sono le condizioni di gara con la creazione / apertura di file in unix, che in alcune circostanze possono portare ad attacchi di escalation di privilegi se il programma con la condizione di competizione viene eseguito con privilegi più elevati rispetto all'utente che interagisce con esso, come un sistema processo daemon o, peggio ancora, il kernel.

Anche se una condizione di competizione ha qualcosa come 10 ^ (- 80) possibilità di accadere casualmente , potrebbe anche accadere che un determinato attaccante abbia una buona possibilità di creare tali condizioni deliberatamente e artificialmente .

    
risposta data 17.08.2012 - 13:30
fonte
6

Therac-25!

Gli sviluppatori del progetto Therac-25 erano abbastanza fiduciosi sulla tempistica tra un'interfaccia utente e un problema relativo all'interfaccia in una macchina XRAY terapeutica.

Non avrebbero dovuto essere.

Puoi saperne di più su questo famoso disastro del software di vita e morte all'indirizzo:

link

o

link

La tua applicazione potrebbe essere molto meno sensibile ai guasti rispetto ai dispositivi medici. Un metodo utile è valutare l'esposizione al rischio come il prodotto della probabilità di accadimento e il costo dell'evento nel corso della vita del prodotto per tutte le unità che potrebbero essere prodotte.

Se hai scelto di costruire il tuo codice per durare (e sembra che tu abbia), dovresti prendere in considerazione la legge di Moore che può facilmente ridurre diversi zeri ogni pochi anni mentre i computer all'interno o all'esterno del tuo sistema diventano più veloci. Se spedisci migliaia di copie, elimina più zeri. Se gli utenti eseguono questa operazione giornalmente (o mensilmente) per anni, ne portano via qualcuna di più. Se viene utilizzato dove è disponibile la fibra di Google, cosa succede? Se l'UI garbage raccoglie le operazioni a metà della GUI, influisce sulla gara? Stai usando una libreria Open Source o Windows dietro la tua GUI? Gli aggiornamenti possono influire sui tempi?

I semafori, i blocchi, i mutex, la sincronizzazione della barriera sono tra i modi per sincronizzare le attività tra i thread. Potenzialmente, se non li stai utilizzando, un'altra persona che mantiene il tuo programma potrebbe e quindi le supposizioni abbastanza veloci sulle relazioni tra i thread possono cambiare e il calcolo della condizione della competizione potrebbe essere invalidato.

Ti consiglio di sincronizzarti esplicitamente perché, mentre potresti non vederlo mai creare un problema, un cliente potrebbe. Inoltre, anche se la tua condizione di gara non si verifica mai, cosa succede se tu o la tua organizzazione siete chiamati in tribunale per difendere il vostro codice (dato che Toyota era imparentata con la Prius qualche anno fa). Più accurata è la tua metodologia, meglio la farai. Potrebbe essere più gentile dire "ci difendiamo da questo caso improbabile come questo ..." piuttosto che dire "sappiamo che il nostro codice fallirà, ma abbiamo annotato questa equazione per dimostrare che non accadrà nella nostra vita. "

Sembra che il calcolo della probabilità provenga da qualcun altro. Conoscono il tuo codice e li conosci abbastanza per credere che non sia stato commesso alcun errore? Se calcolassi un'affidabilità del 99,9997% per qualcosa, potrei anche ripensare ai miei corsi sulle statistiche del college e ricordare che non sempre ho ottenuto il 100%, e retrocedere di alcuni punti percentuali sulle mie stime di affidabilità personale.

    
risposta data 21.08.2012 - 05:17
fonte
4

would it be totally unnecessary or even counterproductive to add more lines of code to hinder readability?

La semplicità è buona solo quando è anche corretta. Poiché questo codice non è corretto, i programmatori futuri lo lo guarderanno inevitabilmente quando cercano un bug correlato.

Indipendentemente dal modo in cui lo gestisci (sia registrandolo, documentandolo o aggiungendo i blocchi - dipende dal costo), risparmierai tempo agli altri programmatori quando guardi il codice.

    
risposta data 17.08.2012 - 16:26
fonte
3

Ciò dipenderebbe dal contesto. Se è un gioco casual per iPhone, probabilmente no. Il sistema di controllo di volo per il prossimo veicolo spaziale con equipaggio, probabilmente. Tutto dipende da quali sono le conseguenze se il risultato "cattivo" si verifica confrontato con il costo stimato di ripararlo.

Raramente c'è una risposta "taglia unica" per questi tipi di domande perché sono domande di programmazione non , ma invece domande di economia.

    
risposta data 17.08.2012 - 05:54
fonte
3

Sì, aspettati l'inaspettato. Ho passato ore (nel codice di altre persone ^^) a rintracciare le condizioni che non dovrebbero mai accadere.

Cose come sempre hanno un altro, hanno sempre un default sul caso, inizializzano le variabili (sì, davvero .. gli errori accadono da questo), controlla i tuoi loop per le variabili riutilizzate per ogni iterazione, ecc.

Se sei preoccupato di inoltrare i problemi in modo specifico, leggi blog, articoli e libri sull'argomento. Il tema attuale sembra essere immutabile.

    
risposta data 17.08.2012 - 17:09
fonte
3

Risolvi.

Ho visto esattamente questo. Un thread riesce a fare una richiesta di rete a un server che esegue una ricerca di database complessa e risponde prima che l'altro thread abbia raggiunto la riga successiva del codice. Succede.

Qualche cliente deciderà un giorno di eseguire qualcosa che accarezza tutta la CPU per il thread "veloce" mentre lascia il thread lento in esecuzione, e ti dispiacerebbe:)

    
risposta data 17.08.2012 - 17:48
fonte
1

Se hai riconosciuto una condizione di gara improbabile, almeno documentala nel codice!

EDIT: dovrei aggiungere che lo aggiusterei se possibile, ma al momento di scrivere quanto sopra, nessun'altra risposta ha esplicitamente detto almeno di documentare il problema nel codice.

    
risposta data 22.08.2012 - 09:01
fonte
0

Penso che se già sai come e perché potrebbe accadere, potrebbe anche affrontarlo. Questo è se non prende una quantità abbondante di risorse.

    
risposta data 17.08.2012 - 15:07
fonte
0

Tutto dipende da quali sono le conseguenze di una condizione di competizione. Penso che le persone che rispondono alla tua domanda siano corrette per la loro linea di lavoro. Il mio è un motore di configurazione del router. Per me, le condizioni di gara rendono i sistemi fermi, corrotti o non configurati, anche se hanno affermato che ha avuto successo. Io uso sempre i semafori per router in modo da non dover pulire nulla a mano.

Penso che parte del mio codice GUI sia ancora soggetto a condizioni di gara in modo tale che a un utente possa essere dato un errore perché è avvenuta una condizione di competizione, ma non avrei tali possibilità se c'è una possibilità di corruzione dei dati o comportamento scorretto dell'applicazione dopo tale evento.

    
risposta data 18.08.2012 - 02:34
fonte
0

Stranamente, ho riscontrato questo problema di recente. Non mi ero neanche reso conto che una circostanza della razza fosse possibile nella mia circostanza. La condizione di gara si è presentata solo quando i processori multi-core sono diventati la norma.

Lo scenario era grosso modo come questo. Un driver di periferica ha generato eventi per il software da gestire. Il controllo doveva tornare al driver del dispositivo il prima possibile per evitare un timeout sul dispositivo. Per garantire ciò, l'evento è stato registrato e accodato in un thread separato.

Receive event from device:
{
    Record event details.
    Enqueue event in the queuing thread.
    Acknowledge the event.
}

Queueing thread receives an event:
{
    Retrieve event details.
    Process event.
    Send next command to device.
}

Questo ha funzionato bene per anni. Poi improvvisamente fallirebbe in certe configurazioni. Si scopre che il thread di accodamento ora funzionava veramente in parallelo al thread di gestione degli eventi, piuttosto che condividere il tempo di un singolo processore. È riuscito a inviare il comando successivo al dispositivo prima che l'evento fosse stato riconosciuto, causando un errore di fuori sequenza.

Dato che ha interessato solo un cliente in una configurazione, ho messo vergognosamente in Thread.Sleep(1000) il problema. Non c'è stato un problema da allora.

    
risposta data 18.08.2012 - 13:01
fonte