2009-03-24 19 views
7

Se ho una variabile locale in questo modo:sicurezza Discussione e le variabili locali

Increment() 
{ 
    int i = getFromDb(); // get count for a customer from db 
}; 

E questa è una classe istanza che viene incrementato (ogni volta che un cliente - un oggetto istanza - fa un acquisto), è questo thread variabile sicuro? Ho sentito che le variabili locali sono thread-safe perché ogni thread ha il suo stack, ecc. Ecc.

Inoltre, ho ragione nel pensare che questa variabile sia condivisa? Quello che mi manca nel reparto di pensiero è che questa variabile funzionerà con diversi oggetti del cliente (ad es. John, Paul, ecc.) Quindi è thread-safe, ma questo è un pensiero imperfetto e un po 'di inesperienza nella programmazione concorrente. Questo suona molto ingenuo, ma poi non ho molta esperienza nella codifica simultanea come faccio in generale, la codifica sincrona.

EDIT: Inoltre, la funzione chiamata getFromDb() non fa parte della domanda e non mi aspetto che nessuno possa indovinare sulla sicurezza del thread in quanto è solo una chiamata per indicare che il valore viene assegnato da una funzione che ottiene dati dal db. :)

EDIT 2: Inoltre, la sicurezza del thread getFromDb è garantita poiché esegue solo operazioni di lettura.

risposta

33

i viene dichiarata come variabile locale (metodo), in modo che solo normalmente esiste nello stack-frame di Increment() - quindi sì, i è sicuro filo ... (anche se non posso commentare su getFromDb).

tranne se:

  • Increment è un blocco iteratore (cioè utilizza yield return o yield break)
  • i viene utilizzato in un metodo anonimo (delegate { i = i + 1;}) o lambda (foo => {i=i+foo;}

Nei due scenari precedenti, ci sono alcuni casi in cui può essere esposto all'esterno dello stack, ma ne dubito o stai facendo entrambi.

noti che campi (variabili sulla classe) sono non thread-safe, in quanto sono banalmente esposti ad altri thread. Ciò è ancora più evidente con i campi static, poiché tutti i thread condividono automaticamente lo stesso campo (ad eccezione dei campi thread-static).

+0

+1 per completezza (discussione sui metodi anon e sui blocchi iteratori. Le classi statiche e la sicurezza del thread sono il concetto più semplice da comprendere, personalmente.) – dotnetdev

+0

IMHO, è importante chiarire che anche nelle eccezioni elencate, la variabile locale è _still_ unico per ogni chiamata al metodo. Cioè, mentre è possibile accedervi al di fuori del contesto del metodo, anche potenzialmente in modalità non thread-safe, saranno comunque thread-safe rispetto alla variabile locale _same_ nel contesto di una chiamata _different_ allo stesso metodo . –

5

La tua dichiarazione ha due parti separate: una chiamata di funzione e un'assegnazione.

L'assegnazione è thread-safe, perché la variabile è locale. Ogni diversa invocazione di questo metodo otterrà la propria versione della variabile locale, ciascuna memorizzata in un diverso stack frame in un altro posto in memoria.

La chiamata a getFromDb() può essere o meno condivisibile, a seconda dell'implementazione.

2

Fintantoché la variabile è locale al metodo, è sicura per i thread. Se fosse una variabile statica, non sarebbe predefinita.

class Example 
{ 
    static int var1; //not thread-safe 

    public void Method1() 
    { int var2; //thread-safe 
    } 
} 
1

Mentre int i è thread-safe, l'intero caso è il caso probabilmente non è thread-safe.Il tuo int i è, come hai detto, thread-safe perché ogni thread ha una propria traccia dello stack e quindi ogni thread ha il suo i. Tuttavia, tutti i thread condividono lo stesso database, pertanto gli accessi al database non sono thread-safe. È necessario sincronizzare correttamente gli accessi al database per assicurarsi che ogni thread visualizzi il database solo al momento giusto.

Come al solito con la concorrenza e il multithreading, non è necessario eseguire la sincronizzazione sul DB se si leggono solo le informazioni. È necessario sincronizzare non appena due thread proveranno a leggere/scrivere lo stesso insieme di informazioni dal DB.

1

Sarò "thread safe" poiché ogni thread avrà la propria copia di i in pila come suggerito. La vera domanda sarà: il contenuto del thread getFromDb() è sicuro?

1

I è una variabile locale quindi non è stato condiviso.

Se getFromDb() legge, ad esempio, una sequenza di oracle o un campo di autoincrement di SQL Server, il db si occupa della sincronizzazione (nella maggior parte degli scenari, escludendo i DB di replica/distribuiti), quindi è possibile restituire in modo sicuro il risultato a qualsiasi thread chiamante. Cioè, il DB sta garantendo che ogni chiamata getFromDB() avrà un valore diverso.

La sicurezza del thread è in genere un po 'di lavoro: la modifica del tipo di una variabile raramente consente di ottenere la sicurezza del thread poiché dipende da come i thread accedono ai dati. Puoi risparmiare mal di testa rielaborando l'algoritmo in modo che utilizzi una coda alla quale tutti gli utenti si sincronizzano invece di cercare di orchestrare una serie di lucchetti/monitor. O meglio ancora rendere l'algoritmo privo di blocco, se possibile.

1

I è thread safe sintatticamente. Ma quando assegni i valori della variabile di istanza, il metodo di istanza restituisce il valore a i, quindi i dati condivisi vengono manipolati da più thread.