Produzione:
L'output di questo esempio mostra il comportamento non definito dell'applicazione poiché l'output del codice è 0 o 10. Ciò è accaduto perché i thread stavano eseguendo contemporaneamente e il comando di lettura avrebbe potuto essere fatto durante l'esecuzione del comando di scrittura. In questo modo, abbiamo ottenuto un risultato incompleto nell'output.
L'Atomico STD può risolvere questo problema e può rendere i comportamenti indefiniti nell'applicazione ben definiti. Per implementare questo, apportiamo semplicemente una piccola modifica durante l'inizializzazione e l'impostazione dei valori e dei tipi di dati delle variabili definite usando "std :: atomic". Definiamo la variabile “A” e “B” come variabili atomiche di "Std :: Nome della variabile atomica". Facciamo anche una piccola modifica nella funzione di scrittura in cui, in precedenza, abbiamo semplicemente assegnato i valori a A e B utilizzando l'operatore di assegnazione "=". Ma qui, assegniamo i valori usando il "nome variabile. Metodo Store (Value) ". Usiamo il "nome variabile. load () "nella funzione di lettura. Il resto è lo stesso dell'esempio precedente.
I valori nell'output vengono letti e scritti in modo ben definito. E il multithreading è anche supportato qui.
Rilasciare e acquisire ordini con memoria (modello)
Il modello di memoria può avere un impatto enorme sulle funzioni di lettura e scrittura dell'Atomico. Il modello di memoria è una funzione predefinita che si assicura della coerenza dell'ordinamento sequenziale. Uno dei modelli atomici più interessanti è il modello di rilascio e acquisizione in cui possiamo archiviare il rilascio dell'ordine di memoria per il primo thread e l'ordine di memoria acquisito per il secondo thread, il che significa che qualsiasi negozio/scrittura atomico o non atomico è fatto Prima nel primo thread prima del secondo thread, io.e. carico.
Quindi, nell'esempio, possiamo persino cambiare la variabile atomica "A" in non atomica e la seconda variabile "B" è mantenuta atomica. Nella funzione di scrittura, archiviamo la variabile non atomica "A" semplicemente assegnandolo qualsiasi valore, e.G. 30. E memorizziamo correttamente il valore per la variabile atomica "b" usando "b. Store (valore, std :: memory_order_release) ". Lo stesso è fatto anche nella funzione di lettura in cui utilizziamo "std :: cout < Produzione:
L'atomicità dell'operazione è ancora mantenuta con il rilascio e il modello di memoria acquisito anche quando avevamo una variabile X non atomica. Questo è successo a causa degli Y (atomico.memorizzare) che ha assicurato la manutenzione della coerenza sequenziale.
Modello di scambio
Exchange significa quando scambiamo il valore di una variabile (atomica) a un altro valore. In cambio, il valore viene prima scambiato e quindi viene restituito il valore precedente che viene scambiato da quello nuovo. Una volta scambiato il valore, si riflette su ogni operazione successiva a tale valore. Implettiamo questo scambio di variabili atomiche con l'aiuto di un esempio.
In questo esempio, introduciamo innanzitutto il foobar variabile atomico globale che ha un valore pari a "15". Nella principale, facciamo un thread come thread1 e gli assegniamo un valore intero uguale a 2. Quindi, nel ciclo per, impostiamo l'indice da 0 a 100 volte. Quindi, sostituiamo il valore della variabile Foobar a 2 usando "Foobar. Exchange (valore) ". Dopodiché, usciamo dal ciclo e cariciamo il valore della variabile Foobar per stamparlo. Dopo aver caricato il valore di Foobar, ora scambiamo il suo valore con 18 con ".Exchange (valore da sostituire con) "Metodo. E poi di nuovo, caricare i valori di Foobar e visualizzarli usando il metodo di stampa.
Qui in questo esempio, il thread deve scambiare i valori per cento volte e il valore di Foobar viene scambiato da 15 a 28. Qualsiasi operazione dopo questo scambio restituisce lo stesso valore che può essere visto nell'output.
Andare a prendere
Fetch è uguale alla funzione di scambio che scrive i valori e restituisce i valori precedentemente recuperati. Questa operazione prende il valore che viene archiviato prima che venga applicata qualsiasi operazione. Ora implementiamo l'aggiunta di recupero e il recupero sottrai in questo esempio. Definiamo una variabile atomica con il tipo di dati non firmato come "conta" e inizializza il conteggio con zero. Quindi, creiamo due funzioni: una per l'aggiunta di recupero e un'altra per sottrarre. Eseguiamo il contatore dell'incremento 1 per l'aggiunta e il decremento 1 per sottrarre in entrambe queste funzioni. Quindi, stampiamo questi valori da entrambe le funzioni Fetch_add e fetch_sub nel principale.
La funzione Fetch_add ha restituito 0 e 1 come valori precedenti prima dell'incremento. Allo stesso modo, il fetch_sub ha restituito 2 e 1 come valori precedentemente memorizzati prima della sottrazione o del decremento di uno.
Conclusione
Abbiamo implementato le operazioni di base in "Std :: Atomic" in questo articolo. Abbiamo imparato come possiamo affrontare i problemi nelle applicazioni multithreading utilizzando l'STD Atomic. Abbiamo implementato i vari esempi in C ++ per le diverse funzioni come Fetch, Exchange, Lettura/Scrittura e Modello di memoria dell'Atomico STD per garantire la coerenza sequenziale e i comportamenti ben definiti del codice per applicazioni multithread.