Domanda

Alcuni linguaggi di fornire un volatile modificatore, che è descritto come l'esecuzione di una "lettura barriera di memoria", prima di leggere la memoria che effettua una variabile.

Una lettura barriera di memoria è comunemente descritto come un modo per garantire che la CPU ha eseguito la legge richiesto prima della barriera prima di eseguire una lettura richiesto dopo la barriera.Tuttavia, l'utilizzo di questa definizione, sembrerebbe che un valore non aggiornato potrebbe essere ancora leggere.In altre parole, eseguito legge in un certo ordine non sembrano significare che la memoria principale o altre Cpu deve essere consultato per verificare che i valori successivi leggere riflettono l'ultimo nel sistema al momento della lettura della barriera o scritto, successivamente, dopo la lettura di barriera.

Quindi, non volatile davvero garantire che un up-to-data valore è o (gasp!) che i valori letti sono almeno come up-to-date, come la legge prima della barriera?O qualche altra interpretazione?Quali sono le implicazioni pratiche di questa risposta?

È stato utile?

Soluzione

Ci sono leggi di barriere e scrivere barriere;acquisire le barriere e rilasciare le barriere.E di più (io vs di memoria, ecc).

Le barriere non sono lì per controllare le "ultime" valore o la "freschezza" dei valori.Sono lì per controllare il relativo ordine di accessi alla memoria.

Scrivere le barriere di controllo l'ordine di scrittura.Perché scrive di memoria sono lento (rispetto alla velocità della CPU), di solito c'è una scrittura di richiesta di coda in cui scrive sono pubblicati prima che realmente accadere".Anche se sono in coda in ordine, mentre con la coda dell'scrive può essere riordinati.(Così magari 'coda' non è il nome migliore...) a Meno che non si utilizza scrivere le barriere per evitare che il riordino.

Leggi le barriere di controllo l'ordine della legge.A causa di esecuzione speculativa (CPU guarda avanti e carica dalla memoria i primi) e a causa dell'esistenza del buffer di scrittura (la CPU di leggere un valore dal buffer di scrittura, invece di memoria, se c'è, cioè CPU pensa solo scritto X = 5, allora perché leggerlo, basta vedere che è ancora in attesa di diventare 5 nel buffer di scrittura) legge può avvenire in ordine.

Questo è vero indipendentemente da ciò che il compilatore cerca di fare per quanto riguarda l'ordine del codice generato.ie 'volatile' in C++, non aiuta qui, perché è solo dice al compilatore di codice di uscita di ri-leggere il valore di "memoria", NON dice che la CPU come e dove leggere (cioè la "memoria" è molte cose a livello CPU).

In modo di leggere/scrivere le barriere mettere dei blocchi per evitare di riordino in lettura/scrittura code (la lettura non è di solito così tanto di coda, ma il riordino effetti sono gli stessi).

Che tipo di blocchi?- acquisire e/o rilasciare i blocchi.

Acquisire - ad esempio leggere-acquisire(x) aggiungere la lettura di x, nella lettura di coda e cancellare la coda (non proprio a filo coda, ma aggiungere un marcatore dicendo che non riordinare nulla prima di questa lettura, che è come se la coda è stata svuotata).In modo che in seguito (in ordine di codice) legge possono essere riordinate, ma non prima che la lettura di x.

Comunicato - ad esempio la scrittura di rilascio(x, 5) flusso (o marker) la coda, poi aggiungere il write-richiesta per la scrittura di coda.Quindi, prima di scrive non essere riordinati a succedere dopo che x = 5, ma nota che scrisse in seguito possono essere riordinate prima di x = 5.

Nota che ho abbinato la lettura con acquisire e scrivere con il rilascio, perché questo è tipico, ma diverse combinazioni sono possibili.

Acquisire e Rilasciare vengono considerati "mezza barriere" o "half-recinzioni', perché solo interrompere il riordino di andare in un solo modo.

Un pieno di barriera (o completa recinzione) si applica sia un'acquisizione e rilascio di ie non di riordino.

In genere per lockfree di programmazione, o C# o java 'volatile', ciò che si vuole/bisogno leggere-lettura e scrittura di rilascio.

ie

void threadA()
{
   foo->x = 10;
   foo->y = 11;
   foo->z = 12;
   write_release(foo->ready, true);
   bar = 13;
}
void threadB()
{
   w = some_global;
   ready = read_acquire(foo->ready);
   if (ready)
   {
      q = w * foo->x * foo->y * foo->z;
   }
   else
       calculate_pi();
}

Quindi, prima di tutto, questo è un brutto modo di thread di programma.Serrature sarebbe più sicuro.Ma solo per illustrare le barriere...

Dopo threadA() viene eseguita la scrittura di pippo, che ha bisogno di scrivere pippo->pronto ULTIMO, davvero l'ultima, altrimenti altri thread possono vedere pippo->pronto presto e male i valori di x/y/z.Quindi, usiamo write_release su pippo->pronto, che, come detto sopra, effettivamente 'vampate' la scrittura di coda (garantendo x,y,z sono impegnati), quindi, aggiunge il pronto=true richiesta di coda.E poi aggiunge il bar=13 richiesta.Nota che, dal momento che abbiamo appena usato una barriera di rilascio (non completa) bar=13 potrebbe essere scritte prima pronto.Ma a noi non importa!cioè stiamo supponendo bar non è la modifica di dati condivisi.

Ora threadB() ha bisogno di sapere che quando si dice "pronto" in realtà intendiamo pronto.Facciamo read_acquire(foo->ready).Questa lettura è aggiunto in coda, la coda è svuotato.Nota che w = some_global potrebbe anche essere ancora in coda.Così pippo-> > > pronti, che possono essere letti prima some_global.Ma di nuovo, non ci interessa, come non fa parte dei dati importanti che ci sono così attenta.Quello che abbiamo è la foo->x/y/z.Così vengono aggiunti a leggere coda dopo l'acquisizione a filo/marcatore, garantendo che essi sono di sola lettura dopo lettura foo->pronto.

Nota anche che questa è in genere la stessa esatta barriere utilizzate per bloccare e sbloccare un mutex/CriticalSection/etc.(ie acquistare sul lock(), la pubblicazione sui unlock() ).

Così,

  • Sono abbastanza sicuro che questo (cioè acquisire/release) è esattamente ciò che MS docs dire accade per la scrittura/lettura di 'volatile' le variabili in C# (e, facoltativamente, per MS C++, ma questo non è standard).Vedere http://msdn.microsoft.com/en-us/library/aa645755(VS.71).aspx tra cui "Una lettura volatile ha "acquisire semantica";che è, è garantito che si verificano prima di qualsiasi riferimento alla memoria che si verificano dopo di esso..."

  • Io pensare java è lo stesso, anche se io non sono così familiari.Ho il sospetto che sia esattamente lo stesso, perché in genere non hanno bisogno di maggiori garanzie di leggere-acquisire/scrittura-release.

  • Nella tua domanda che eravamo sulla strada giusta quando si pensa che è davvero tutto è relativo ordine - hai avuto l'ordinamenti indietro (vale a dire "i valori letti sono almeno come up-to-date, come la legge prima della barriera?"- no, la legge prima che la barriera non sono importanti, la sua legge DOPO la barriera, che sono garantiti per essere DOPO, viceversa per le scrive).

  • E si prega di notare, come detto, riordino accade in lettura e scrittura, in modo che solo utilizzando una barriera in un thread e non l'altro NON FUNZIONA.cioè una scrittura di rilascio non è sufficiente senza la lettura-acquisire.cioè anche se si scrive nel giusto ordine, si poteva leggere nell'ordine sbagliato se non si usa l'leggere le barriere di andare con la scrittura di barriere.

  • E, infine, notare che il blocco di programmazione e di CPU e di memoria di architetture possono essere in realtà molto più complicato di così, ma attaccare con l'acquisizione di rilascio si arriva molto lontano.

Altri suggerimenti

volatile nella maggior parte dei linguaggi di programmazione non implica una vera e propria CPU leggere barriera memoria, ma un ordine al compilatore di non ottimizzare la legge tramite la cache in un registro. Ciò significa che la lettura processo / thread otterrà il valore "fine". Una tecnica comune è quella di dichiarare una bandiera volatile booleano da impostare in un gestore di segnale e controllò nel ciclo principale del programma.
CPU contrasto barriere di memoria vengono direttamente forniti sia tramite istruzioni della CPU o implicita determinati mnemonico assemblatore (come prefisso lock in x 86) e sono utilizzati per esempio quando si parla di dispositivi hardware in cui l'ordine di lettura e scrittura alla memoria mappata IO registri è importante o la sincronizzazione di accesso alla memoria in ambiente multi-elaborazione.
Per rispondere alla tua domanda - no, barriera di memoria non garantisce valore "ultimo", ma garantisce ordine delle operazioni di accesso alla memoria. Questo è fondamentale per esempio nei senza blocchi di programmazione .
Qui è uno dei primer sulle barriere di memoria della CPU.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top