En informática, un modelo de memoria describe las interacciones de los hilos a través de la memoria y su uso compartido de los datos .
Un modelo de memoria permite que un compilador realice muchas optimizaciones importantes. Las optimizaciones del compilador, como la fusión de bucles, mueven las sentencias en el programa, lo que puede influir en el orden de las operaciones de lectura y escritura de las variables potencialmente compartidas . Los cambios en el orden de las lecturas y escrituras pueden provocar condiciones de carrera . Sin un modelo de memoria, un compilador puede no aplicar dichas optimizaciones a programas multiproceso, o puede aplicar optimizaciones que sean incompatibles con el multiproceso, lo que genera errores.
Por lo tanto, los lenguajes de programación modernos como Java implementan un modelo de memoria. El modelo de memoria especifica barreras de sincronización que se establecen mediante operaciones de sincronización especiales y bien definidas, como la adquisición de un bloqueo mediante la entrada en un bloque o método sincronizado. El modelo de memoria estipula que los cambios en los valores de las variables compartidas solo deben hacerse visibles para otros subprocesos cuando se alcanza dicha barrera de sincronización. Además, la noción completa de una condición de carrera se define sobre el orden de las operaciones con respecto a estas barreras de memoria. [1]
Esta semántica les da a los compiladores optimizadores un mayor grado de libertad al aplicar optimizaciones: el compilador solo necesita asegurarse de que los valores de las variables (potencialmente compartidas) en las barreras de sincronización sean iguales tanto en el código optimizado como en el no optimizado. En particular, el compilador supone que reordenar las instrucciones en un bloque de código que no contiene ninguna barrera de sincronización es seguro.
La mayor parte de la investigación en el área de modelos de memoria gira en torno a:
El modelo de memoria de Java fue el primer intento de proporcionar un modelo de memoria de subprocesos completo para un lenguaje de programación popular. [2] Después de que se estableció que los subprocesos no se podían implementar de forma segura como una biblioteca sin colocar ciertas restricciones en la implementación y, en particular, que los estándares C y C++ ( C99 y C++03 ) carecían de las restricciones necesarias, [3] [4] el subcomité de subprocesos de C++ se puso a trabajar en un modelo de memoria adecuado; en 2005, presentaron el documento de trabajo C n1131 [5] para que el Comité C se uniera a sus esfuerzos. La revisión final del modelo de memoria propuesto, C++ n2429, [6] fue aceptada en el borrador del estándar C++ en la reunión de octubre de 2007 en Kona. [7] El modelo de memoria se incluyó luego en los siguientes estándares C++ y C, C++11 y C11 . [8] [9] El lenguaje de programación Rust heredó la mayor parte del modelo de memoria de C/C++. [10]
El modelo de memoria de Java describe qué comportamientos son legales en código multiproceso y cómo los subprocesos pueden interactuar a través de la memoria. Describe la relación entre las variables de un programa y los detalles de bajo nivel de almacenamiento y recuperación de las mismas en la memoria o los registros de un sistema informático real. Lo hace de una manera que se puede implementar correctamente utilizando una amplia variedad de hardware y una amplia variedad de optimizaciones del compilador.
Las bibliotecas de subprocesos de C++ se encuentran en la incómoda situación de tener que especificar (implícita o explícitamente) un modelo de memoria extendido para C++ con el fin de especificar la ejecución del programa. Proponemos integrar un modelo de memoria adecuado para la ejecución multiproceso en el estándar de C++.
Este [link farm] proporciona información relacionada con el esfuerzo por aclarar el significado de los programas multiproceso de C++ y proporcionar algunas API estándar relacionadas con subprocesos donde actualmente no existen.
Rust hereda de forma bastante descarada el modelo de memoria para los átomos de C++20.