Espacios de nombres
Variantes
Acciones

Modelo de memoria y acceso concurrente

De cppreference.com
< cpp‎ | language

Define la semántica del almacenamiento en memoria de la computadora para el propósito de la máquina abstracta de C ++.

La memoria disponible para un programa en C++ es uno o más secuencias continuas de bytes. Cada byte en memoria tiene una única dirección.

Contenido

[editar] Byte

Un byte es la unidad de memoria más pequeña direccionable. Se define como una secuencia contigua de bits, de tamaño suficiente para albergar el valor de cualquier unidad de código UTF-8 (256 valores distintos) (desde C++14) y cualquier miembro del conjunto de caracteres básicos de ejecución (los 96 caracteres que se requiere que sen un byte). Al igual que en C, C++ soporta bytes de tamaño de 8 bits y mayores.

Los tipos char, unsigned char, y signed char usan un solo byte para almacenar y representación del valor. Se puede conocer el número de bits de un byte mediante CHAR_BIT o std::numeric_limits<unsigned char>::digits.

[editar] Localización en memoria

Una localización en memoria es

  • Un objeto de tipo escalar (tipo aritmético, tipo puntero, tipo enumeración o std::nullptr_t)
  • o la secuencia mayor contigua de campos de bits que no tenga tamaño cero.

Nota: varias características del lenguaje, como referencias y funciones virtuales, pueden incluir localizaciones adicionales de memoria que no son accesibles al programa pero que son administrados por la implementación.

struct S {
    char a;     // localización de memoria #1
    int b : 5;  // localización de memoria #2
    int c : 11, // localización de memoria #2 (continúa)
          : 0,
        d : 8;  // localización de memoria #3
    struct {
        int ee : 8; // localización de memoria #4
    } e;
} obj; // El objeto 'obj' consiste en 4 localizaciones de memoria separadas


[editar] Hilos y acceso concurrente a datos

Un hilo de ejecución es un flujo de control en un programa que comienza con la invocación de una función de alto nivel por std::thread::thread, std::async, u otros medios.

Cualquier hilo tiene la posibilidad de acceder al cualquier objeto en el programa (los objetos con duración de almacenamiento automático y local a hilo aún pueden ser accedidos por otro hilo a través de un puntero o por referencia).

Siempre se permite que diferentes hilos de ejecución accedan (leer y modificar) a diferentes localizaciones de memoria concurrentemente, sin interferencia y sin necesidad de sincronización.

Cuando la evaluación de una expresión escribe en una localización de memoria y otra evaluación lee o modifica la misma localización, se dice que las expresiones entran en conflicto. Un programa que tiene dos evaluaciones en conflicto tiene un problema de concurrencia a menos que

Si ocurre un problema de concurrencia, el comportamiento del programa es indetermiando.

(en particular, la implementación de std::mutex está sincronizado con, y por lo tanto, ocurre antes de la adquisición del mismo mutex por otra hilo, lo que hace posible el uso de bloqueos mutex para protegerse de problemas de concurrencia)

int cnt = 0;
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // comportamiento indeterminado
std::atomic<int> cnt{0};
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // OK

[editar] Orden de memoria

Cuando un hilo lee un valor en una ubicación de memoria, puede ver el valor inicial, el valor escrito en el mismo hilo, o el valor escrito por otro hilo. Vea std::memory_order para obtener detalles sobre el orden en que las escrituras hechas por hilos se hacen visibles a otros hilos.

[editar] Progreso hacia delante

[editar] Libre de obstrucción

Cuando sólo un hilo que no está bloqueado en una función de la biblioteca estándar ejecuta una función atómica que esta libre de bloqueos, se garantiza que la ejecución se completa (Todas las operaciones sin bloqueos de la biblioteca estándar están libres de obstrucción)

[editar] Libre de bloqueo

Cuando una o más funciones atómicas libres de bloqueo se ejecutan concurrentemente, se garantiza que al menos una de ellas se completa (todas las operaciones libres de bloqueo de la biblioteca estándar son libres de bloqueo – es trabajo de la implementación asegurar que no se puedan bloquear de forma indefinida por otros hilos, como robar continuamente la línea de chacé)

[editar] Garantía de progreso

En un programa C++ válido, cada hilo está realizando una de las acciones siguientes

  • finalizar
  • realizar una llamada a función de la biblioteca de E/S
  • realizar una acceso mediante un glvalue volátil
  • realizar una operación atómica o de sincronización

Ningún hilo de ejecución puede ejecutarse para siempre sin realizar ninguno de estos comportamientos observables.

Tenga en cuenta que esto significa que un programa con recursividad infinita o bucle infinito (implementado como una sentencia for o por un goto en bucle o de otra manera) tiene un comportamiento indeterminado. Esto permite a los compiladores eliminar todos los bucles que no tienen un comportamiento observable, sin tener que comprobar que eventualmente pueden terminar.

Se dice que un hilo progresa si realiza uno de los pasos de ejecución anteriores (E/S, volátil, atómico, o sincronización), está bloqueado en una función de la biblioteca estándar, o llama a una función atómica libre de bloqueo que no se completa debido a un hilo concurrente no bloqueado.

Progreso hacia delante concurrente

Si un hilo ofrece garantía de progreso hacia delante concurrente, progresará (como se definió anteriormente) en un tiempo finito, mientras no haya terminado, independientemente de si hay otros hilos (si hay alguno) en progreso.

El estándar aconseja, pero no exige que el hilo principal y los hilos iniciados por std::thread garanticen progreso hacia delante concurrente.

Progreso hacia delante paralelo

Si un hilo ofrece garantía de progreso paralelo, no se requiere que la implementación asegure que el hilo progresará si aún no ha ejecutado ningún paso de ejecución (E/S, volátil, atómica, o sincronización), pero una vez que este hilo ha ejecutado un paso, proporciona garantías de progreso hacia delante concurrente (esta regla describe un hilo en un grupo de hilos que ejecutan tareas en orden arbitrario).

Progreso hacia delante débilmente paralelo

Si un hilo ofrece garantía de progreso débilmente paralelo, no se garantiza el progreso, independientemente de que los otros hilos progresen o no.

Todavía se puede garantizar que esos hilos progresen mediante bloqueo con delegación de garantía de progreso: si un hilo P bloquea de esta forma en la finalización de un conjunto de hilos S, entonces al menos un hilo de S ofrecerá garantía de progreso que será igual o más fuerte que P. Una vez que el hilo se completa, otro hilo en S se fortalecerá de manera similar. Una vez que el conjunto está vacío, P se desbloqueará.

Los algoritmos paralelos de las bibliotecas estándar de C++ bloquean con delegación de progreso en la finalización de un conjunto inespecífico de hilos gestionados por la biblioteca.

(desde C++17)

[editar] Ver también

Documentacion C de Modelo de memoria