2013-04-07 27 views
9

So che dichiarare una variabile statica all'interno di una funzione in C significa che la variabile mantiene il suo stato tra le chiamate di funzioni. Nel contesto dei thread, ciò comporterà che la variabile mantenga il suo stato su più thread o che abbia uno stato separato tra ciascun thread?Variabili e filettature statiche (C)

Qui è un passato domanda esame di carta Ho difficoltà a rispondere:

La seguente funzione C è destinato ad essere utilizzato per assegnare identificatori univoci (UID) ai suoi interlocutori:

get_uid() 
{ 
static int i = 0; 
return i++; 
} 

Spiegare in che modo get_uid() potrebbe funzionare in modo errato in un ambiente in cui è chiamato da più thread. Utilizzando uno scenario di esempio specifico, fornire dettagli specifici su su come e perché potrebbe verificarsi un comportamento errato.

Al momento presumo che ogni thread abbia uno stato separato per la variabile, ma non sono sicuro che sia corretto o se la risposta dipenda più dalla mancanza di mutua esclusione. Se questo è il caso, allora come potrebbero essere implementati i semafori in questo esempio?

+0

La tua domanda finale, hai chiesto come si possono * implementare i semafori * in questo esempio. Intendi chiedere come potrebbe essere implementato * usando * semafori? – WhozCraig

+0

Se si utilizza gcc, una bella aggiunta allo standard sono le variabili __thread statiche. Sono variabili statiche, ma locali per ogni thread. Lo trovo particolarmente utile per la gestione delle connessioni thread-locale a un server ... – user1251840

risposta

14

L'assunzione (le discussioni hanno una propria copia) non è corretta. Il problema principale del codice è quando più thread chiamano tale funzione get_uid(), c'è una possibile condizione di gara su quale thread incrementa i e ottiene l'ID che potrebbe non essere univoco.

+0

Esatto, quindi due thread che entrano nella funzione allo stesso tempo incrementano i due volte e quindi ritornano con lo stesso valore? – dahui

+0

Sì, è una possibilità. –

+0

Vedo, grazie amico! – dahui

3

No, se si desidera una variabile il cui valore dipende dalla discussione in cui viene utilizzato, si dovrebbe avere uno sguardo a Thread Local Storage.

Una variabile statica, si può immaginare davvero come una variabile completamente globale. È praticamente lo stesso. Quindi è condiviso da tutto il sistema che conosce il suo indirizzo.

EDIT: anche come un commento ricorda che, se si mantiene questa implementazione come una variabile statica, condizioni di gara potrebbe fare che il valore i viene incrementato al tempo stesso da più thread, il che significa che non si dispone di qualsiasi idea del valore che verrà restituito dalla funzione chiama. In questi casi, è necessario proteggere l'accesso tramite i cosiddetti oggetti di sincronizzazione come mutexes o critical sections.

+1

L'esempio di codice soffre anche di aggiornamenti non atomici, il che significa che più thread potrebbero essenzialmente generare un singolo incremento. – WhozCraig

+0

@WhozCraig è giusto ... –

+0

Grande, grazie ragazzi – dahui

1

Dato che questo sembra un compito a casa, risponderò solo una parte di questo e cioè ogni thread condividerà la stessa copia di i. IOW, i thread non ottengono le proprie copie. Lascerò a voi l'esclusione reciproca.

+0

Non è compito ma revisione per gli esami! Probabilmente imparerò di più dal mio lavoro, quindi grazie. – dahui

1

Ogni thread condividerà la stessa variabile statica che è probabilmente una variabile globale. Lo scenario in cui alcuni thread possono avere un valore errato è la condizione di competizione (l'incremento non viene eseguito in una singola esecuzione, piuttosto è fatto in 3 istruzioni di assemblaggio, carico, incremento, memorizzazione). Leggi qui e lo schema al link lo spiega bene.

Race Condition

+0

Leggere ora, grazie uomo – dahui

+0

prego. Una risposta alla risposta potrebbe farmi sapere che la risposta ti ha aiutato :) – nommyravian

+0

Ho provato, il mio rappresentante non è ancora abbastanza alto per un upvote: P – dahui

8

Tutti i fili di un processo condividono lo stesso spazio di indirizzi. Poiché i è una variabile statica, ha un indirizzo fisso. Il suo "stato" è solo il contenuto della memoria a quell'indirizzo, che è condiviso da tutti i thread.

L'operatore postfix ++ incrementa il suo argomento e restituisce il valore dell'argomento prima dell'incremento. L'ordine in cui vengono eseguiti non è definito. Una possibile implementazione è

copy i to R1 
copy R1 to R2 
increment R2 
copy R2 to i 
return R1 

Se più di un thread è in esecuzione, entrambi possono essere in esecuzione queste istruzioni simultaneamente o intervallati. Lavora per te stesso sequenze in cui ottenere risultati diversi. (Si noti che ogni thread ha il proprio stato di registro, anche per i thread in esecuzione sulla stessa CPU, poiché i registri vengono salvati e ripristinati quando si passano i thread.)

Una situazione come questa dove ci sono risultati diversi a seconda dell'indeterminazione l'ordinamento delle operazioni in diversi thread è chiamato race condition, perché c'è una "corsa" tra i diversi thread su quale delle due operazioni viene eseguita prima.

+0

@ user2253489 Puoi ricompensare una bella risposta con un upvote. Puoi anche cambiare la tua selezione se ti piace abbastanza. –

+0

Il mio rappresentante non è ancora abbastanza alto per l'upvoting. Provai! – dahui

+1

Devi amare quei ragazzi che non conoscono minimamente la spiegazione:/ – dahui

1

Se si utilizza gcc è possibile utilizzare le funzioni atomic builtin. Non sono sicuro di ciò che è disponibile per altri compilatori.

int get_uid() 
{ 
    static int i = 0; 
    return __atomic_fetch_add(&i, 1, __ATOMIC_SEQ_CST); 
} 

Ciò garantisce che la variabile non possa essere attivata da più di un thread alla volta.

+0

Questa è una buona informazione, ma non è una risposta alla domanda ... dovrebbe essere un commento. –

Problemi correlati