Tutte le condizioni di gara sono valide? [chiuso]

1

Ho appena scritto la seguente parte di codice (in delphi):

procedure Update(Value: Integer);
begin
  // If the last update was yesterday, replace yesterday value
  if CompareDate(FLastUpdate,Now) <> 0 then
  begin
    FYesterdayValue := FTodayValue;
  end;
  FTodayValue := Value;
  FLastUpdate := Now;
end;

E ho capito che contiene una condizione di gara piccola, ma reale. Immagina che la prima volta che viene chiamata la funzione "Ora" sia un millisecondo prima di mezzanotte, l'istruzione if viene saltata e il timestamp viene aggiornato con un'altra chiamata a "Ora", che è ora un millisecondo DOPO mezzanotte. Ora il timestamp ha il valore sbagliato e il valore FYesterdayValue non ottiene il valore corretto.

In pratica, penso che le possibilità che questo accada mai sono quasi inesistenti perché a) il codice è tipicamente chiamato ~ 1 / minuto eb) il tempo di CPU tra le due chiamate sarà ESTREMAMENTE piccolo.

Tuttavia è un bug e sono curioso di correggerlo se ci si è imbattuti in un progetto.

    
posta monoceres 04.03.2014 - 15:18
fonte

2 risposte

11

Come regola generale, i problemi valgono la pena quando il beneficio atteso supera il costo previsto. La sicurezza dei thread non fa eccezione a questa regola, è solo che il modo di calcolare il rischio che determina il costo previsto è particolarmente complesso e poco compreso da molti.

Per cominciare, la sicurezza del threading non è sul radar di molte persone. Assumeranno semplicemente "Questo non viene mai chiamato in modo concorrente, nulla può andare storto". E spesso non lo è. Altre volte lo è (ad esempio, la CPU si è bloccata per un tempo inaspettatamente grande perché l'intera app ora vive in una macchina virtuale sovrascritta ...), e quindi nessuno ha la più pallida idea di cosa potrebbe essere successo. In altre parole, la probabilità di una gara effettivamente in corso è spesso molto difficile da stimare.

L'impatto è spesso più facile da capire: se si registrano elementi informativi in un registro di controllo interno, tende ad essere basso; se la data che stai mantenendo è legata alla business logic (forse determina quando la licenza di abbonamento del tuo cliente scade?), allora potrebbe essere catastroficamente pessima.

Senza conoscere il contesto di questo codice, non posso prevedere cosa dovrebbe essere fatto. Ma quasi certamente non è una buona idea notare una possibile condizione di competizione e non fare nulla al riguardo, semplicemente convincendo te stesso che non sarà un problema. Innanzitutto, come ho detto, è particolarmente difficile prevedere se sarà un problema o meno. Secondo, se la condizione fosse probabile, dovresti avere per occuparsene, quindi avere essere in grado di proteggere il tuo codice. E se capisci come farlo (di solito non è quello difficile), ci sono relativamente poche ragioni per non farlo tutto il tempo come una questione di principio - solo per evitare di convincerti "Ah , Non ho bisogno di preoccuparmi per l'istanza questa , questo non accadrà mai ", che è un classico esempio di" ultime parole famose ".

    
risposta data 04.03.2014 - 15:50
fonte
3

Correggere questo bug, non solo a causa della condizione di competizione, ma anche perché la versione in cui si chiama Now una volta all'inizio e il salvataggio è molto più facile da ragionare in generale.

Fondamentalmente, più una funzione è prevedibile, più è facile da capire. Now è, in un certo senso, molto imprevedibile (potrebbe restituire valori diversi ogni volta che viene chiamato), e quindi ogni volta che lo chiami, rendi la tua funzione meno prevedibile e più difficile da capire.

In quanto tale, mi piace molto il suggerimento di Rory di ridimensionare completamente la chiamata a Now dalla funzione. Ora è ancora più prevedibile e, come sottolinea, unità testabile.

    
risposta data 04.03.2014 - 16:19
fonte

Leggi altre domande sui tag