2016-04-17 53 views
5

Supponendo che x sia una variabile inter-thread condivisa e func restituisca sempre 0, il codice seguente contiene una corsa di dati in termini di C11 e C++ 11? Si supponga che x sia scritto in due thread diversi, sempre con un lock appropriato, tranne l'istruzione switch qui sotto.L'accesso non protetto alla variabile condivisa è sempre una corsa di dati?

int x; // global variable 

... 

int y; // local variable 

... 

switch (func()) 
{ 
    case 1: 
    { 
    x = 0; 
    y = 1; 
    break; 
    } 
    case 2: 
    { 
    x = 0; 
    y = 2; 
    break; 
    } 
    case 3: 
    default: 
    { 
    y = 3; 
    break; 
    } 
} 

c'è una nota nella norma (sia C11 e C++ 11) che preclude trasformazioni compilatore che introduce una gara di dati al codice. Il compilatore è autorizzato a trasformare il codice come di seguito? Il codice qui sotto contiene certamente una corsa di dati, ma la domanda è se il compilatore l'ha introdotta o se era già nel codice originale. C'era un accesso non protetto a una variabile condivisa, sebbene irraggiungibile.

int x; // global variable 

... 

int y; // local variable 

... 

temp = x; 
x = 0; 
switch (func()) 
{ 
    case 1: 
    { 
    y = 1; 
    break; 
    } 
    case 2: 
    { 
    y = 2; 
    break; 
    } 
    case 3: 
    default: 
    { 
    x = temp; 
    y = 3; 
    break; 
    } 
} 
+0

senza meccanismi di sincronizzazione si aspettano gare di dati, sì si dovrebbe piuttosto avere un 'std :: atomiche x;' –

+0

Sì, assolutamente –

+0

non è solo.. una corsa dati C non ha un concetto di processi concorrenti – Olaf

risposta

4

Nello standard C++, una corsa è definito:

1,10/4: due valutazioni espressione conflitto se uno di loro modifica una locazione di memoria e l'altro accessi o modifica la stessa posizione di memoria.

1,10/21: L'esecuzione di un programma contiene una gara di dati se contiene due azioni contrastanti in diversi fili, almeno uno dei che non è atomico, e né avviene prima dell'altro. Qualsiasi prova di dati produce un comportamento indefinito.

Supponendo che si dispone di più thread in esecuzione lo stesso codice, a causa del fatto che func() sarebbe sempre restituire 0 (il vostro reclamo), nessuno dei fili potrebbe cambiare il contenuto di x. Inoltre, y è una variabile locale di una funzione eseguita da un thread, quindi non è condivisa. Quindi, nessuna condizione di competizione potrebbe verificarsi in questo scenario.

Il compilatore non è consentito effettuare le trasformazioni corrispondenti al secondo frammento di perché:

1,10/22: trasformazioni compilatore che introducono assegnazioni ad una posizione di memoria potenzialmente condivisa che non sarebbero modificato dal La macchina astratta è generalmente preclusa da questo standard, dal momento che tale incarico potrebbe sovrascrivere un'altra assegnazione con una diversa filettatura nei casi in cui un'esecuzione astratta della macchina non avrebbe avuto durante una corsa di dati.

Ma se te scrivere il frammento, alle condizioni sopra esposte potrebbe incontrare condizioni di gara dal momento che la x non è atomica, e ci potrebbe essere letto in un solo filo (temp=x) e scrivere l'accesso a l'altro (sia x=0 . o nella sezione di default l'altro thread (x=temp)

+0

Grazie per la risposta, questo è quello che mi aspetterei, tuttavia ho dei dubbi in un punto. Non capisco come il fatto che * func * restituisca sempre 0 influenza la relazione * happen-before * tra le assegnazioni a x nell'istruzione switch e altri accessi a x in thread diversi. – mrn

+1

@mrn Non c'è nessun prima di happpens tra thread diversi da quello fornito dalla sincronizzazione. – Yakk

+0

Le relazioni Happens-before sono uno strumento per analizzare la propagazione sequenziale che deriva dalla sincronizzazione dei thread durante l'esecuzione. Se nessuno dei thread usa la variabile condivisa non vi è altro effetto di ordinamento oltre al fatto che il valore iniziale è accaduto per il resto. A proposito, non vedo sincronizzare il tuo codice, e x non è atomico. quindi se funct restituirebbe qualcosa di diverso da 0, le razze potrebbero verificarsi perché non c'è nulla che assicurasse un ordine di accesso a quella variabile. – Christophe