Domanda

Qual è il modello di memoria per la concorrenza in C ++ 03?

(E, C ++ 11 cambia il modello di memoria per supportare meglio la concorrenza?)

È stato utile?

Soluzione

Il modello di memoria C ++ è la specifica di quando e perché la memoria fisica viene letta / scritta rispetto al codice C ++.

Fino al prossimo standard C ++, il modello di memoria C ++ è lo stesso di C. Nello standard C ++ 0x, è previsto l'inclusione di un modello di memoria appropriato per il multithreading (vedere qui ), e sarà probabilmente parte della prossima revisione dello standard C, C1X. Quello attuale è rudimentale:

  • specifica solo il comportamento delle operazioni di memoria osservabili dal programma corrente.
  • non dice nulla sugli accessi simultanei alla memoria quando più processi accedono alla stessa memoria (non esiste alcuna nozione di memoria o processi condivisi).
  • non dice nulla sugli accessi simultanei alla memoria quando più thread accedono alla stessa memoria (non esiste una nozione di thread).
  • non offre alcun modo per specificare un ordinamento per gli accessi alla memoria (le ottimizzazioni del compilatore includono il movimento del codice e gli accessi al riordino dei processori recenti, entrambi possono interrompere modelli come l'inizializzazione con doppio controllo).

Quindi, lo stato corrente è: le operazioni di memoria C ++ sono specificate solo quando hai 1 processo, con il suo thread principale e non scrivere codice che dipende da un ordinamento specifico di variabili di lettura / scrittura e basta. In sostanza, questo significa che, a parte il tradizionale programma Hello World, sei fregato.

Naturalmente, ti verrà chiesto di aggiungere che "funziona oggi sulla mia macchina, non puoi avere ragione " . La frase corretta sarebbe "funziona oggi sulla mia macchina con questa combinazione specifica di hardware, sistema operativo (libreria di thread) e compilatore che si conoscono abbastanza da implementare qualcosa che funziona in qualche modo ma probabilmente si romperà in alcuni punto ".

Ok ok, questo è un po 'duro ma infernale, persino Herb Sutter lo riconosce (leggi solo l'introduzione) e sta parlando di tutte le versioni pre 2007 di una delle più diffuse toolchain C / C ++ ...

Il comitato standard C ++ tenta di trovare qualcosa che affronterà tutti questi problemi pur essendo meno vincolante (e quindi con prestazioni migliori) rispetto al modello di memoria di Java.

Hans Boehm ha raccolto qui alcuni suggerimenti su articoli sull'argomento, sia accademici, e dal comitato C ++.

Altri suggerimenti

Vedendo alcune altre risposte, sembra che molti programmatori C ++ non siano nemmeno consapevoli di quale sia il "modello di memoria" stai chiedendo dei mezzi.

Le domande riguardano il modello di memoria nel senso: quali sono le garanzie (se ce ne sono) sul riordino in scrittura / lettura (che può accadere sul lato del compilatore o sul runtime)? Questa domanda è molto importante per la programmazione multithread, poiché senza tali regole non è possibile scrivere programmi multithread corretti, e una verità un po 'sorprendente è con l'attuale mancanza di modello di memoria esplicita che molti programmi multithread funzionano più o meno "per pura fortuna" - il più delle volte grazie ai compilatori che assumono l'alias puntatore tra le chiamate di funzione. - vedi I thread non possono essere implementati come libreria

Nell'attuale C ++ non esiste un modello di memoria standard. Alcuni compilatori definiscono il modello di memoria per variabili volatili, ma questo non è standard. C ++ 0x definisce il nuovo "atomico" primitivi per questo scopo. Un punto di partenza esaustivo per verificare lo stato recente è disponibile all'indirizzo Discussioni e modello di memoria per C ++

I collegamenti importanti sono anche Modello di memoria di concorrenza , Tipi atomici e Ordine di dipendenza dei dati C ++: modello di atomica e memoria proposte standard.

Purtroppo in C ++ non esiste un "Modello di memoria standard" come quello di Java. L'implementazione effettiva è lasciata al compilatore, alle librerie di runtime e ai processori.

Quindi il modello di memoria C ++ == caotico mix-mash di modelli, il che significa che devi sempre provare a scrivere un codice sicuro che non dipende da un modello di memoria specifico, e che vale anche per la programmazione thread, perché il il compilatore può fare qualsiasi ottimizzazione desideri al di fuori di una sezione critica, anche fuori dall'ordinamento!

Che dire del controllo dei documenti sul sito web del comitato standard C ++:

Se desideri avere una comprensione più approfondita dei modelli di coerenza della memoria condivisa, ti rimando al seguente tutorial.

http://rsim.cs.uiuc.edu/~sadve /Publications/computer96.pdf

Risposta breve: nessuna

Risposta lunga: C ++ non ha memoria gestita, devi allocarla e liberarla tu stesso. Le classi di puntatori intelligenti possono rendere questo meno oneroso. Se dimentichi di liberare memoria che hai allocato, si tratta di una perdita di memoria e di un bug. Se provi a usare la memoria dopo averla liberata, o provi a liberare memoria più di una volta, anche questi sono cattivi bug.

Per quanto riguarda i dettagli di basso livello, C ++ non lo specifica: dipende dall'hardware. Si accede alla memoria tramite puntatori, che contengono una sorta di indirizzo di memoria. Gli indirizzi di memoria possono essere indirizzi fisici o virtuali. Vedrai gli indirizzi fisici solo se stai lavorando su un kernel del sistema operativo o se stai leggendo il vecchio codice DOS eseguito in modalità reale. Per maggiori dettagli, leggi memoria virtuale , ci sono molte buone risorse là fuori.

L'architettura x86 consente anche di indirizzare la memoria utilizzando i descrittori di segmento. Questa è un'altra lattina di worm, che non è stata utilizzata dai tempi di Win16, e se sei fortunato, non dovrai mai occupartene.

In poche parole, il modello di memoria C ++ è costituito da ...

  • Uno stack che cresce verso il basso, ovvero quando si preme un frame dello stack il puntatore dello stack ha un valore inferiore a quello che era

  • Un heap che cresce verso l'alto, ovvero l'indirizzo finale della memoria appena allocata è maggiore rispetto a prima della memoria. Allocare memoria nell'heap usando malloc () o new. Se la memoria disponibile non è sufficiente nell'heap, malloc (o new) chiama la funzione di sistema brk () sbrk () per aumentare la dimensione dell'heap. Se la chiamata a brk () o sbrk () fallisce, allora malloc o new falliscono con un'eccezione di memoria esaurita.

Non dovresti mai preoccuparti se lo stack o l'heap crescono o crescono e in alcuni sistemi questi potrebbero funzionare al contrario. Considera solo che stack e heap crescono verso l'interno dalle estremità dello spazio degli indirizzi.

  • Un allocatore di memoria, malloc, che alloca memoria in termini di byte a 8 bit. Nuovo alloca anche la memoria, ma la quantità di memoria che alloca si basa sulla dimensione dell'oggetto che viene rinnovato.

  • Spazio testo che contiene il codice eseguibile. Il testo risiede sotto l'heap. Non è possibile modificare lo spazio di testo durante l'esecuzione

Un programma può avere altre sezioni speciali sotto il testo.

Puoi vedere come un programma è organizzato staticamente (prima che sia caricato) usando objdump su sistemi Linux.

Ho notato che sebbene tu non lo abbia menzionato nella tua domanda, "concorrenza" è una delle parole chiave che hai assegnato a questa domanda. I sistemi di threading assegnano ulteriore spazio thread sull'heap per ciascun thread e quindi gestiscono il puntatore dello stack per passare da un thread all'altro.

Ci sono molti più dettagli, molti dei quali specifici per hardware, sistemi operativi o threading particolari, ma questa è l'idea essenziale.

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