2013-05-24 15 views
18

Supponiamo che ci sia una funzione (funzione membro possibilmente)statico inizializzazione delle variabili locali in un ambiente multithreading

SomeType foo() 
{ 
    static SomeType var = generateVar(); 
    return var; 
} 

Come sarà inizializzato var se foo si chiamerà 'per la prima volta' da più thread contemporaneamente?

  1. È garantito che generateVar() verrà chiamato solo una volta in qualsiasi scenario (se utilizzato naturalmente)?
  2. È garantito che foo restituirà lo stesso valore quando viene chiamato più volte in qualsiasi scenario?
  3. C'è una differenza di comportamento per i tipi primitivi o non primitivi?

risposta

24

riguardante C++ 03:

La macchina astratta definito dal C++ 03 standard non contiene una definizione formale di ciò che un filo è, e quello che il risultato di un programma dovrebbe essere se un oggetto è accessibile contemporaneamente.

Non v'è alcuna nozione di primitiva di sincronizzazione, ordine delle operazioni eseguite in diversi thread, dati corsa, e così via. Pertanto, per definizione, ogni programma C++ 03 a più thread contiene un comportamento non definito.

Ovviamente, in pratica le implementazioni forniscono un comportamento documentato, ma non c'è nulla nello Standard che specifica quale dovrebbe essere questo comportamento. Pertanto, direi che dipende dal tuo compilatore.

Il resto della risposta si concentrerà su C++ 11, che definisce la semantica delle operazioni simultanee.

Per quanto riguarda C++ 11:

si garantisce che generateVar() sarà chiamato solo una volta in qualsiasi scenario (se utilizzato ovviamente)?

No, non in nessuno scenario.

L'inizializzazione var è garantito per essere thread-safe, quindi generateVar() non saranno inseriti contemporaneamente, ma se viene generata un'eccezione da generateVar(), o il costruttore di copia o spostare costruttore SomeType (se SomeType è un UDT , ovviamente), quindi l'inizializzazione verrà tentata di nuovo la volta successiva che il flusso di esecuzione entra nella dichiarazione, il che significa che generateVar() verrà richiamato di nuovo.

al comma 6.7/4 del C++ 11 serie su l'inizializzazione delle variabili blocco-scope con durata di conservazione statica:

[...] Se le uscite di inizializzazione di un'eccezione , l'inizializzazione non è completa, quindi verrà tentata di nuovo la volta successiva che il controllo entra nella dichiarazione.Se il controllo immette contemporaneamente alla dichiarazione durante l'inizializzazione della variabile, l'esecuzione simultanea deve attendere il completamento dell'inizializzazione . Se il controllo rientra nella dichiarazione in modo ricorsivo mentre la variabile è inizializzata, il comportamento non è definito. [...]

Per quanto riguarda la prossima domanda:

E 'garantito che foo restituirà lo stesso valore quando chiamato più volte in qualsiasi scenario?

Se riuscirà a restituire un valore (vedere sopra), allora sì.

Esiste una differenza di comportamento per i tipi primitivi o non primitivi?

No, non c'è, tranne che non c'è una tale cosa come un costruttore di copia o spostamento di costruzione per i tipi primitivi, quindi v'è anche il rischio che copia-inizializzazione si tradurrà in un'eccezione (a meno che non ovviamente generateVar() lanci).

+0

"l'inizializzazione verrà tentata la prossima volta"? Come è stato realizzato? AFAIK una variabile statica viene inizializzata quando il modulo viene caricato e ciò accade una sola volta durante la vita del processo. – Devolus

+3

@Devolus: una variabile statica in un ambito di blocco viene inizializzata quando la sua dichiarazione viene soddisfatta dal flusso di esecuzione. Ho aggiunto una citazione dallo Standard –

+0

@AndyProwl: grazie per la tua risposta. Puoi chiarire cosa accadrà in C++ 98? – Andrew

Problemi correlati